From e36748b693cc0679b820b0912d9baf8e224dbea8 Mon Sep 17 00:00:00 2001 From: Troy Howard <thoward37@gmail.com> Date: Wed, 4 Jun 2025 03:04:45 -0500 Subject: [PATCH 1/3] Add Harness CI/CD integration documentation --- .../continuous-delivery/_index.md | 4 + .../continuous-delivery/harness.md | 733 ++++++++++++++++++ .../partner/azure-infrastructure-as-code.md | 2 +- static/logos/tech/ci-cd/harness.svg | 11 + 4 files changed, 749 insertions(+), 1 deletion(-) create mode 100644 content/docs/iac/using-pulumi/continuous-delivery/harness.md create mode 100644 static/logos/tech/ci-cd/harness.svg diff --git a/content/docs/iac/using-pulumi/continuous-delivery/_index.md b/content/docs/iac/using-pulumi/continuous-delivery/_index.md index 6112f4f2a08a..4d77b2d86f47 100644 --- a/content/docs/iac/using-pulumi/continuous-delivery/_index.md +++ b/content/docs/iac/using-pulumi/continuous-delivery/_index.md @@ -57,6 +57,10 @@ Pulumi can easily integrate into any continuous integration/continuous delivery <img src="/logos/tech/ci-cd/gitlab-ci.svg" alt="GitLab CI"> <h4 class="no-anchor">GitLab CI</h4> </a> + <a href="/docs/iac/using-pulumi/continuous-delivery/harness"> + <img src="/logos/tech/ci-cd/harness.svg" alt="Harness"> + <h4 class="no-anchor">Harness</h4> + </a> <a href="/docs/iac/using-pulumi/continuous-delivery/google-cloud-build"> <img src="/logos/tech/ci-cd/google-cloud-build.png" alt="Google Cloud Build"> <h4 class="no-anchor">Google Cloud Build</h4> diff --git a/content/docs/iac/using-pulumi/continuous-delivery/harness.md b/content/docs/iac/using-pulumi/continuous-delivery/harness.md new file mode 100644 index 000000000000..8c79bc1a4848 --- /dev/null +++ b/content/docs/iac/using-pulumi/continuous-delivery/harness.md @@ -0,0 +1,733 @@ +--- +title_tag: "Using Harness | CI/CD" +meta_desc: This page details how to use Harness CI/CD to deploy infrastructure with Pulumi + and manage Harness resources using the Pulumi Harness provider. +title: Harness +h1: Pulumi CI/CD & Harness +meta_image: /images/docs/meta-images/docs-meta.png +menu: + iac: + name: Harness + parent: iac-using-pulumi-cicd + weight: 7 +--- + +[Harness](https://www.harness.io/) is a modern software delivery platform that provides comprehensive CI/CD, feature flags, cloud cost management, and security testing capabilities. This page shows how to use Harness CI/CD to deploy infrastructure with Pulumi and how to manage Harness platform resources using the Pulumi Harness provider. + +Pulumi doesn't require any particular arrangement of stacks or workflow to work in a continuous integration / continuous deployment system. The steps described here can be altered to fit into any existing deployment setup. + +## Prerequisites + +- An account on [https://app.pulumi.com](https://app.pulumi.com) +- The latest Pulumi CLI + - [Installation instructions](/docs/install/) +- A Harness account and access to Harness CI/CD +- A git repository connected to your Harness project +- [Pulumi Harness provider](/registry/packages/harness/) (optional, for managing Harness resources) + +## Setting Up Harness CI/CD with Pulumi + +### Authentication and Secrets Management + +Authentication for both Pulumi and your cloud provider can be managed in several ways. We recommend using [Pulumi ESC (Environments, Secrets, and Configuration)](/docs/esc/) as your primary secrets management solution, as it provides centralized, secure configuration management that works seamlessly across different CI/CD platforms. + +#### Option 1: Using Pulumi ESC (Recommended) + +With Pulumi ESC, you can centralize all your secrets and configuration in one place: + +1. **Create a Pulumi ESC environment** with your secrets: + +```yaml +# esc-environment.yaml +values: + pulumiConfig: + pulumi:access-token: + fn::secret: "your-pulumi-access-token" + aws: + AWS_ACCESS_KEY_ID: + fn::secret: "your-aws-access-key" + AWS_SECRET_ACCESS_KEY: + fn::secret: "your-aws-secret-key" + AWS_REGION: "us-east-1" + environmentVariables: + PULUMI_ACCESS_TOKEN: ${pulumiConfig.pulumi:access-token} + AWS_ACCESS_KEY_ID: ${aws.AWS_ACCESS_KEY_ID} + AWS_SECRET_ACCESS_KEY: ${aws.AWS_SECRET_ACCESS_KEY} + AWS_REGION: ${aws.AWS_REGION} +``` + +2. **Configure your Harness pipeline** to use ESC: + +```yaml +- step: + type: Run + name: Load Pulumi ESC Environment + identifier: load_esc_env + spec: + shell: Bash + command: | + # Install and use ESC CLI to inject environment variables + curl -fsSL https://get.pulumi.com/esc/install.sh | sh + export PATH=$PATH:$HOME/.pulumi/bin + + # Open ESC environment and export variables + eval "$(esc open your-org/your-environment --format shell)" + + # These variables are now available for subsequent steps + echo "Environment loaded successfully" + envVariables: + PULUMI_ACCESS_TOKEN: <+secrets.getValue("PULUMI_ACCESS_TOKEN")> +``` + +#### Option 2: Using Harness Secrets + +If you prefer to manage secrets directly in Harness, navigate to your project's **Secrets** section and add: + +1. **`PULUMI_ACCESS_TOKEN`** - [Create a Pulumi access token](/docs/pulumi-cloud/accounts#access-tokens) +2. **Cloud provider credentials**: + - AWS: `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `AWS_REGION` + - Azure: `ARM_CLIENT_ID`, `ARM_CLIENT_SECRET`, `ARM_TENANT_ID`, `ARM_SUBSCRIPTION_ID` + - Google Cloud: `GOOGLE_CREDENTIALS` + +### Pipeline Configuration + +Create a `.harness/` directory in your repository with your pipeline configuration. Here's an example pipeline that runs `pulumi preview` on pull requests and `pulumi up` on commits to the main branch: + +```yaml +pipeline: + name: Pulumi Infrastructure + identifier: pulumi_infrastructure + projectIdentifier: your_project_id + orgIdentifier: your_org_id + tags: {} + stages: + - stage: + name: Preview Infrastructure + identifier: preview_infrastructure + description: Preview infrastructure changes on pull requests + type: CI + spec: + cloneCodebase: true + platform: + os: Linux + arch: Amd64 + runtime: + type: Cloud + spec: {} + execution: + steps: + - step: + type: Run + name: Install Dependencies + identifier: install_dependencies + spec: + shell: Bash + command: | + # Install Pulumi CLI + curl -fsSL https://get.pulumi.com | sh + export PATH=$PATH:$HOME/.pulumi/bin + + # Install language-specific dependencies + case "<+pipeline.variables.language>" in + "typescript"|"javascript") + npm install + ;; + "python") + pip install -r requirements.txt + ;; + "go") + go mod download + ;; + "csharp") + dotnet restore + ;; + esac + - step: + type: Run + name: Pulumi Preview + identifier: pulumi_preview + spec: + shell: Bash + command: | + export PATH=$PATH:$HOME/.pulumi/bin + cd <+pipeline.variables.workingDirectory> + + # Login to Pulumi + pulumi login + + # Select the stack + pulumi stack select <+pipeline.variables.stackName> + + # Run preview + pulumi preview + envVariables: + PULUMI_ACCESS_TOKEN: <+secrets.getValue("PULUMI_ACCESS_TOKEN")> + AWS_ACCESS_KEY_ID: <+secrets.getValue("AWS_ACCESS_KEY_ID")> + AWS_SECRET_ACCESS_KEY: <+secrets.getValue("AWS_SECRET_ACCESS_KEY")> + AWS_REGION: <+secrets.getValue("AWS_REGION")> + when: + pipelineStatus: Success + condition: <+trigger.event> == "PR" + - stage: + name: Deploy Infrastructure + identifier: deploy_infrastructure + description: Deploy infrastructure changes on main branch + type: CI + spec: + cloneCodebase: true + platform: + os: Linux + arch: Amd64 + runtime: + type: Cloud + spec: {} + execution: + steps: + - step: + type: Run + name: Install Dependencies + identifier: install_dependencies_deploy + spec: + shell: Bash + command: | + # Install Pulumi CLI + curl -fsSL https://get.pulumi.com | sh + export PATH=$PATH:$HOME/.pulumi/bin + + # Install language-specific dependencies + case "<+pipeline.variables.language>" in + "typescript"|"javascript") + npm install + ;; + "python") + pip install -r requirements.txt + ;; + "go") + go mod download + ;; + "csharp") + dotnet restore + ;; + esac + - step: + type: HarnessApproval + name: Infrastructure Approval + identifier: infra_approval + spec: + message: Please review the infrastructure changes before deployment + includePipelineExecutionHistory: true + approvers: + userGroups: + - account.Infrastructure_Team + timeout: 1d + when: + stageStatus: Success + condition: <+pipeline.variables.requireApproval> == "true" + - step: + type: Run + name: Pulumi Up + identifier: pulumi_up + spec: + shell: Bash + command: | + export PATH=$PATH:$HOME/.pulumi/bin + cd <+pipeline.variables.workingDirectory> + + # Login to Pulumi + pulumi login + + # Select the stack + pulumi stack select <+pipeline.variables.stackName> + + # Deploy infrastructure + pulumi up --yes + envVariables: + PULUMI_ACCESS_TOKEN: <+secrets.getValue("PULUMI_ACCESS_TOKEN")> + AWS_ACCESS_KEY_ID: <+secrets.getValue("AWS_ACCESS_KEY_ID")> + AWS_SECRET_ACCESS_KEY: <+secrets.getValue("AWS_SECRET_ACCESS_KEY")> + AWS_REGION: <+secrets.getValue("AWS_REGION")> + when: + pipelineStatus: Success + condition: <+trigger.sourceBranch> == "main" + variables: + - name: stackName + type: String + description: The Pulumi stack to deploy + value: "dev" + - name: workingDirectory + type: String + description: Directory containing Pulumi project + value: "infra" + - name: language + type: String + description: Programming language (typescript, python, go, csharp) + value: "typescript" + - name: requireApproval + type: String + description: Whether to require approval for deployments + value: "true" +``` + +## Use Cases + +### Use Case 1: Infrastructure as Code for Application Platforms + +You can use Harness to deploy applications while leveraging Pulumi to manage the underlying infrastructure. This creates a powerful combination where: + +1. **Pulumi manages infrastructure**: Virtual machines, networking, databases, and Kubernetes clusters +2. **Harness manages applications**: Deployments, feature flags, and application lifecycle +3. **Integration through stack outputs**: Pulumi stack outputs provide connection details to Harness deployments + +Example workflow: +```bash +# Infrastructure pipeline (Pulumi) +pulumi up --stack production-infra + +# Get infrastructure outputs +CLUSTER_ENDPOINT=$(pulumi stack output clusterEndpoint) +DATABASE_CONNECTION=$(pulumi stack output databaseConnectionString) + +# Pass to application deployment (Harness) +harness deploy --cluster $CLUSTER_ENDPOINT --database $DATABASE_CONNECTION +``` + +### Use Case 2: Managing Harness Platform Configuration with Pulumi + +Use the [Pulumi Harness provider](/registry/packages/harness/) to manage your Harness platform configuration as code: + +{{< chooser language "typescript,python,go,csharp" >}} + +{{% choosable language typescript %}} + +```typescript +import * as harness from "@pulumi/harness"; + +// Create a project +const project = new harness.platform.Project("myProject", { + identifier: "my_project", + name: "My Project", + orgId: "default", + color: "#0063F7", + modules: ["CI", "CD", "CV"], +}); + +// Create an environment +const environment = new harness.platform.Environment("production", { + identifier: "production", + name: "Production", + orgId: "default", + projectId: project.identifier, + tags: ["env:production"], + type: "Production", +}); + +// Create a service +const service = new harness.platform.Service("webApp", { + identifier: "web_app", + name: "Web Application", + orgId: "default", + projectId: project.identifier, +}); + +// Create a connector for your cloud provider +const awsConnector = new harness.platform.ConnectorAwsSecret("awsConnector", { + identifier: "aws_connector", + name: "AWS Connector", + orgId: "default", + projectId: project.identifier, + secretManagerRef: "account.harnessSecretManager", + region: "us-east-1", + delegateSelectors: ["harness-delegate"], +}); +``` + +{{% /choosable %}} +{{% choosable language python %}} + +```python +import pulumi_harness as harness + +# Create a project +project = harness.platform.Project("my-project", + identifier="my_project", + name="My Project", + org_id="default", + color="#0063F7", + modules=["CI", "CD", "CV"] +) + +# Create an environment +environment = harness.platform.Environment("production", + identifier="production", + name="Production", + org_id="default", + project_id=project.identifier, + tags=["env:production"], + type="Production" +) + +# Create a service +service = harness.platform.Service("web-app", + identifier="web_app", + name="Web Application", + org_id="default", + project_id=project.identifier +) + +# Create a connector for your cloud provider +aws_connector = harness.platform.ConnectorAwsSecret("aws-connector", + identifier="aws_connector", + name="AWS Connector", + org_id="default", + project_id=project.identifier, + secret_manager_ref="account.harnessSecretManager", + region="us-east-1", + delegate_selectors=["harness-delegate"] +) +``` + +{{% /choosable %}} +{{% choosable language go %}} + +```go +package main + +import ( + "github.com/pulumi/pulumi-harness/sdk/go/harness/platform" + "github.com/pulumi/pulumi/sdk/v3/go/pulumi" +) + +func main() { + pulumi.Run(func(ctx *pulumi.Context) error { + // Create a project + project, err := platform.NewProject(ctx, "myProject", &platform.ProjectArgs{ + Identifier: pulumi.String("my_project"), + Name: pulumi.String("My Project"), + OrgId: pulumi.String("default"), + Color: pulumi.String("#0063F7"), + Modules: pulumi.StringArray{pulumi.String("CI"), pulumi.String("CD"), pulumi.String("CV")}, + }) + if err != nil { + return err + } + + // Create an environment + _, err = platform.NewEnvironment(ctx, "production", &platform.EnvironmentArgs{ + Identifier: pulumi.String("production"), + Name: pulumi.String("Production"), + OrgId: pulumi.String("default"), + ProjectId: project.Identifier, + Tags: pulumi.StringArray{pulumi.String("env:production")}, + Type: pulumi.String("Production"), + }) + if err != nil { + return err + } + + // Create a service + _, err = platform.NewService(ctx, "webApp", &platform.ServiceArgs{ + Identifier: pulumi.String("web_app"), + Name: pulumi.String("Web Application"), + OrgId: pulumi.String("default"), + ProjectId: project.Identifier, + }) + if err != nil { + return err + } + + return nil + }) +} +``` + +{{% /choosable %}} +{{% choosable language csharp %}} + +```csharp +using Pulumi; +using Pulumi.Harness.Platform; + +class Program +{ + static Task<int> Main() => Deployment.RunAsync(() => { + // Create a project + var project = new Project("myProject", new ProjectArgs + { + Identifier = "my_project", + Name = "My Project", + OrgId = "default", + Color = "#0063F7", + Modules = new[] { "CI", "CD", "CV" } + }); + + // Create an environment + var environment = new Environment("production", new EnvironmentArgs + { + Identifier = "production", + Name = "Production", + OrgId = "default", + ProjectId = project.Identifier, + Tags = new[] { "env:production" }, + Type = "Production" + }); + + // Create a service + var service = new Service("webApp", new ServiceArgs + { + Identifier = "web_app", + Name = "Web Application", + OrgId = "default", + ProjectId = project.Identifier + }); + + return new Dictionary<string, object?> + { + ["projectId"] = project.Identifier, + ["environmentId"] = environment.Identifier, + ["serviceId"] = service.Identifier + }; + }); +} +``` + +{{% /choosable %}} + +{{< /chooser >}} + +### Use Case 3: Internal Developer Platform (IDP) Integration + +If you're using Harness as part of an Internal Developer Platform, Pulumi can be integrated to provision infrastructure that applications depend on. This is particularly valuable when: + +1. **Self-service infrastructure**: Developers can trigger infrastructure provisioning through Harness workflows +2. **Template-driven deployments**: Use Pulumi templates that developers can customize through Harness parameters +3. **Environment standardization**: Ensure consistent infrastructure across different teams and projects + +Example IDP integration: + +```yaml +# Template pipeline for infrastructure provisioning +pipeline: + name: IDP Infrastructure Template + identifier: idp_infra_template + templateInputs: + - name: applicationName + type: String + description: Name of the application + - name: environment + type: String + description: Target environment (dev/staging/prod) + allowedValues: + - dev + - staging + - prod + - name: instanceSize + type: String + description: Instance size for the application + allowedValues: + - small + - medium + - large + stages: + - stage: + name: Provision Infrastructure + type: CI + spec: + execution: + steps: + - step: + name: Generate Infrastructure + type: Run + spec: + command: | + # Use Pulumi template with dynamic configuration + pulumi new aws-typescript --name <+pipeline.variables.applicationName> + + # Configure based on template inputs + pulumi config set aws:region us-east-1 + pulumi config set instanceSize <+pipeline.variables.instanceSize> + pulumi config set environment <+pipeline.variables.environment> + + # Deploy infrastructure + pulumi up --yes +``` + +## Advanced Configuration + +### Environment-Specific Infrastructure Management + +Pulumi excels at managing different environments with varying infrastructure needs. You can structure your infrastructure to handle the unique requirements of development, staging, and production environments: + +#### Development Environment +- **Smaller resource allocations**: Use smaller instance sizes and fewer replicas +- **Relaxed security**: Allow broader access for debugging and testing +- **Cost optimization**: Use spot instances or scaled-down services +- **Rapid iteration**: Enable features like auto-scaling and blue-green deployments + +```typescript +const config = new pulumi.Config(); +const environment = config.require("environment"); + +const instanceType = environment === "dev" ? "t3.micro" : + environment === "staging" ? "t3.small" : "t3.large"; + +const cluster = new aws.ecs.Cluster("app-cluster", { + capacityProviders: environment === "dev" ? ["FARGATE_SPOT"] : ["FARGATE"], +}); +``` + +#### Staging Environment +- **Production-like configuration**: Mirror production settings for accurate testing +- **Data isolation**: Use production-sized databases with test data +- **Security testing**: Enable security scanning and compliance checks +- **Performance testing**: Scale to handle load testing scenarios + +#### Production Environment +- **High availability**: Multi-zone deployments with redundancy +- **Enhanced security**: Strict network policies and encryption +- **Monitoring and alerting**: Comprehensive observability stack +- **Backup and disaster recovery**: Automated backup procedures + +### Approval Gates and Workflow Integration + +Harness approval gates work particularly well with Pulumi workflows. You can implement different approval strategies: + +#### Infrastructure Change Approvals +Use approval gates specifically for infrastructure changes that require review: + +```yaml +- step: + type: HarnessApproval + name: Infrastructure Security Review + identifier: security_review + spec: + message: "Infrastructure changes detected. Please review security implications." + includePipelineExecutionHistory: true + approvers: + userGroups: + - account.Security_Team + - account.Infrastructure_Team + approverInputs: + - name: securityApproved + type: String + allowedValues: + - approved + - rejected + timeout: 2d + when: + stageStatus: Success + condition: <+pipeline.variables.hasInfraChanges> == "true" +``` + +#### Environment-Specific Approvals +Different environments can have different approval requirements: + +```yaml +- step: + type: HarnessApproval + name: Production Deployment Approval + identifier: prod_approval + spec: + message: "Production infrastructure deployment requires approval" + approvers: + userGroups: + - account.Production_Approvers + minimumCount: 2 + when: + stageStatus: Success + condition: <+pipeline.variables.environment> == "production" +``` + +#### Application Deployment Gates +Coordinate infrastructure and application deployments with sequential approval gates: + +```yaml +stages: + - stage: + name: Infrastructure Deployment + # Pulumi infrastructure deployment + - stage: + name: Infrastructure Validation + type: Approval + spec: + approvers: + userGroups: + - account.Infrastructure_Team + - stage: + name: Application Deployment + # Harness application deployment + dependsOn: + - Infrastructure Validation +``` + +### Multi-Stack Deployments + +For complex environments with multiple stacks, you can configure your Harness pipeline to deploy multiple stacks in sequence: + +```yaml +- step: + type: Run + name: Deploy Infrastructure Stack + identifier: deploy_infra + spec: + shell: Bash + command: | + pulumi stack select infrastructure + pulumi up --yes + +- step: + type: Run + name: Deploy Application Stack + identifier: deploy_app + spec: + shell: Bash + command: | + pulumi stack select application + pulumi up --yes + when: + stageStatus: Success +``` + +## Best Practices + +1. **Use Secrets Management**: Prefer Pulumi ESC for centralized secrets management, with Harness secrets as a secondary option for platform-specific needs. + +2. **Environment Configuration**: Use different Pulumi stacks and ESC environments for each deployment target (dev/staging/production). + +3. **Resource Tagging**: Tag your infrastructure resources with environment and ownership information for better cost management and organization. + +4. **Pipeline Validation**: Always run `pulumi preview` before `pulumi up` to review changes. + +5. **Approval Gates**: Implement appropriate approval gates based on environment criticality and change scope. + +6. **Rollback Strategy**: Implement proper rollback mechanisms using Pulumi's stack history: + +```bash +# Rollback to previous deployment +pulumi stack history +pulumi stack export --version <previous-version> > previous-state.json +pulumi stack import previous-state.json +``` + +7. **IDP Integration**: When using Harness as an IDP, provide templates and self-service capabilities that abstract infrastructure complexity from developers. + +## Troubleshooting + +Common issues and solutions: + +1. **Authentication Failures**: Ensure all required secrets are properly configured in Harness or Pulumi ESC. + +2. **Stack Not Found**: Verify stack names and ensure stacks exist in the Pulumi Cloud. + +3. **Resource Conflicts**: Use `pulumi refresh` to sync state with actual cloud resources. + +4. **Pipeline Timeouts**: Increase timeout values for long-running infrastructure deployments. + +For additional troubleshooting, see our [CI/CD troubleshooting guide](/docs/iac/using-pulumi/continuous-delivery/troubleshooting-guide). + +## Next Steps + +- Explore the [Pulumi Harness provider documentation](/registry/packages/harness/) +- Learn about [Pulumi ESC](/docs/esc/) for advanced secrets and configuration management +- Check out [Pulumi Deployments](/docs/pulumi-cloud/deployments/) for additional CI/CD capabilities +- Review [Harness CI/CD documentation](https://docs.harness.io/category/zgffarnh1m-ci-category) for platform-specific features +- Explore [Harness IDP documentation](https://docs.harness.io/docs/internal-developer-portal) for internal developer platform capabilities \ No newline at end of file diff --git a/content/partner/azure-infrastructure-as-code.md b/content/partner/azure-infrastructure-as-code.md index ae1f2fbd5a8e..216134ce0af6 100644 --- a/content/partner/azure-infrastructure-as-code.md +++ b/content/partner/azure-infrastructure-as-code.md @@ -161,7 +161,7 @@ detail_sections: - title: Use familiar tools and services icon: code icon_color: yellow - description: Pulumi supports IDEs like Visual Studio and VS Code, package managers like NuGet Gallery, common test frameworks, and developer tools like GitHub and Azure DevOps. + description: Pulumi supports IDEs like Visual Studio and VS Code, package managers like NuGet Gallery, common test frameworks, and developer tools like GitHub, Azure DevOps, and Harness. resources: azure: diff --git a/static/logos/tech/ci-cd/harness.svg b/static/logos/tech/ci-cd/harness.svg new file mode 100644 index 000000000000..25ccf1fcab0d --- /dev/null +++ b/static/logos/tech/ci-cd/harness.svg @@ -0,0 +1,11 @@ +<svg width="81" height="17" viewBox="0 0 81 17" fill="none" xmlns="http://www.w3.org/2000/svg"> +<g clip-path="url(#clip0_7225_43052)"> +<path d="M16.9673 5.56561L12.5764 1.27749C12.0564 0.798006 11.437 0.432892 10.76 0.20678C9.2598 -0.280386 7.76681 0.0998812 6.55768 1.27749L2.15595 5.56561C1.66437 6.07281 1.29004 6.67696 1.05822 7.33728C0.55696 8.80053 0.946827 10.2568 2.15595 11.4344L6.55229 15.7225C7.07146 16.2022 7.69031 16.5673 8.36688 16.7932C8.77674 16.9284 9.20624 16.9982 9.63888 17C10.6935 17 11.7032 16.5654 12.5692 15.7225L16.9637 11.4344C17.4559 10.9274 17.8309 10.3232 18.0632 9.66271C18.5627 8.19946 18.1728 6.74497 16.9637 5.56561H16.9673ZM9.8994 2.52169C10.2315 2.62555 10.5376 2.7963 10.7977 3.02288L12.0967 4.29162L9.56343 6.76074L7.03019 4.28986L8.33633 3.01412C8.68667 2.67415 9.18075 2.31316 9.90299 2.51994L9.8994 2.52169ZM3.43515 8.16792C3.54196 7.84374 3.71766 7.54518 3.95078 7.29172L5.24974 6.02473L7.78298 8.49561L5.24794 10.9665L3.9418 9.69075C3.59146 9.35078 3.22315 8.86888 3.43335 8.16441L3.43515 8.16792ZM9.22386 14.473C8.89133 14.3701 8.5851 14.1993 8.32555 13.9719L7.03019 12.7189L9.56343 10.2463L12.0967 12.7171L10.7905 13.9929C10.4402 14.3328 9.9479 14.6938 9.22386 14.4871V14.473ZM15.6917 8.83908C15.5849 9.1629 15.4099 9.46135 15.1779 9.71528L13.8789 10.9665L11.3457 8.49561L13.8789 6.02473L15.1851 7.29873C15.5354 7.63869 15.9037 8.1206 15.6935 8.82506" fill="#00ADE4"/> +<path d="M26.4481 14.5378H28.7173V8.39569C28.7173 6.50135 27.5369 5.10295 25.5229 5.10295C24.5419 5.10295 23.4909 5.52702 22.9447 6.30684V1.75061H20.6774V14.5326H22.9447V9.68722C22.9447 8.55517 23.5268 7.13923 24.8869 7.13923C26.0852 7.13923 26.4481 7.79287 26.4481 8.85658V14.5378ZM35.6109 10.9051C35.6109 12.2562 34.621 12.994 33.2178 12.994C32.5153 12.994 31.8847 12.5559 31.8847 11.8532C31.8847 11.1154 32.5512 10.7124 33.2358 10.6598L35.6109 10.4846V10.9051ZM37.5009 14.6798C37.8882 14.6921 38.2723 14.6077 38.6166 14.4345V12.8187C38.5224 12.8404 38.426 12.8521 38.3292 12.8538C37.9519 12.8538 37.8082 12.6961 37.8082 12.2737V8.88637C37.8365 8.26073 37.7445 7.63545 37.5369 7.04284C36.9979 5.67247 35.6289 5.1818 34.0281 5.1818C31.9386 5.1818 30.2641 6.0948 30.1384 8.14861H32.3177C32.3716 7.30571 32.9824 6.85009 34.0281 6.85009C35.3055 6.85009 35.6109 7.42837 35.6109 8.2888V8.85132L32.8549 9.03883C31.0726 9.16149 29.6874 10.1621 29.6874 11.9005C29.6874 13.3935 30.8391 14.7622 33.0723 14.7622C34.4036 14.7622 35.4833 14.1313 35.9163 13.3935C35.9882 14.0787 36.5272 14.6745 37.4991 14.6745L37.5009 14.6798ZM44.5707 7.35302C44.6908 7.35388 44.8107 7.36148 44.93 7.3758V5.30797C44.833 5.30797 44.7359 5.28695 44.6407 5.28695C43.5412 5.28695 42.4255 5.72505 41.9943 6.77824L41.7949 5.40962H39.8851V14.5396H42.1542V9.93956C42.1542 8.46404 42.9824 7.35828 44.5653 7.35828L44.5707 7.35302ZM51.6709 14.5431H53.9221V8.44652C53.9221 6.55042 52.7507 5.1818 50.7528 5.1818C49.6749 5.1818 48.5574 5.6199 47.9986 6.58372L47.8369 5.40786H45.9523V14.5378H48.2016V10.8175C48.2016 10.0447 48.1837 9.09666 48.5088 8.37642C48.8143 7.70876 49.3371 7.21808 50.1258 7.21808C51.3134 7.21808 51.6727 7.86822 51.6727 8.93894L51.6709 14.5431ZM61.3098 9.06511H57.2638C57.2539 8.55035 57.4258 8.04792 57.7507 7.64217C57.9378 7.41436 58.1769 7.23234 58.4489 7.11064C58.7209 6.98894 59.0183 6.93092 59.3173 6.94121C59.5787 6.92759 59.8401 6.96731 60.0848 7.05783C60.3295 7.14836 60.5521 7.28769 60.7385 7.46693C61.0978 7.85421 61.2972 8.37992 61.3152 9.06511H61.3098ZM63.5645 10.0482C63.6005 8.9074 63.4388 7.87173 62.7543 6.86936C61.9817 5.72855 60.7205 5.18531 59.3407 5.18531C58.7878 5.16957 58.2374 5.2642 57.7233 5.46339C57.2092 5.66258 56.7422 5.96212 56.3511 6.34364C55.4528 7.23911 55.0018 8.53764 55.0018 9.99563C55.0018 11.4887 55.5049 12.7697 56.4391 13.6476C56.8298 14.0174 57.2924 14.3073 57.7997 14.5002C58.3069 14.6931 58.8486 14.7852 59.3928 14.7709C60.5804 14.7709 61.75 14.4029 62.5423 13.4899C62.9016 13.0676 63.2807 12.3491 63.3346 11.8041H61.1786C61.1029 12.0968 60.9471 12.364 60.7277 12.5769C60.4043 12.8923 60.009 13.015 59.3604 13.015C58.8405 13.0133 58.3422 12.8119 57.9735 12.4542C57.7404 12.2169 57.5595 11.9356 57.4418 11.6276C57.3241 11.3197 57.2721 10.9915 57.2889 10.6633H63.5466C63.5466 10.4688 63.5645 10.0482 63.5645 10.0482ZM66.5865 7.95935C66.5918 7.74634 66.6634 7.53994 66.7918 7.3675C66.9201 7.19507 67.0991 7.06474 67.3051 6.99378C67.6152 6.88035 67.9466 6.83257 68.2771 6.85359C68.7242 6.84144 69.1601 6.99127 69.5006 7.27416C69.7359 7.50247 69.8711 7.81094 69.8779 8.13459H72.0212C71.9943 7.42971 71.699 6.75992 71.193 6.25602C70.5103 5.53403 69.3766 5.18355 68.2609 5.18355C67.0895 5.18355 66.105 5.51651 65.4169 6.09655C65.1096 6.34678 64.8643 6.66143 64.6991 7.01705C64.5339 7.37266 64.4531 7.76006 64.4629 8.15036C64.4629 9.30869 65.327 10.3268 66.6044 10.5914C67.4327 10.7667 68.3687 10.8193 69.197 10.9419C69.7719 11.0295 70.133 11.38 70.133 11.9075C70.133 12.9081 68.9814 13.0658 68.225 13.0658C67.5764 13.0658 67.1632 12.9432 66.8021 12.6628C66.5532 12.4454 66.3863 12.1529 66.3278 11.8321H64.2077C64.2948 12.5523 64.6396 13.2195 65.1815 13.716C65.9558 14.4362 67.0177 14.7674 68.207 14.7674C69.4844 14.7674 70.654 14.452 71.4104 13.716C71.6791 13.454 71.89 13.1412 72.03 12.7967C72.1699 12.4522 72.2361 12.0834 72.2243 11.713C72.2243 10.2725 71.1463 9.35952 69.6677 9.1317C68.7496 8.99151 68.516 8.97399 67.6698 8.86884C67.1668 8.79875 66.5919 8.60423 66.5919 7.95585L66.5865 7.95935ZM78.5142 8.13109H80.6504C80.6235 7.42621 80.3282 6.75642 79.8222 6.25252C79.1377 5.53403 78.004 5.18355 76.8955 5.18355C75.7259 5.18355 74.7395 5.51651 74.0514 6.09655C73.7442 6.34678 73.4988 6.66143 73.3336 7.01705C73.1684 7.37266 73.0877 7.76006 73.0974 8.15036C73.0974 9.30869 73.9616 10.3268 75.239 10.5914C76.0672 10.7667 77.0033 10.8193 77.8315 10.9419C78.4064 11.0295 78.7676 11.38 78.7676 11.9075C78.7676 12.9081 77.6141 13.0658 76.8596 13.0658C76.211 13.0658 75.7978 12.9432 75.4366 12.6628C75.1878 12.4454 75.0208 12.1529 74.9623 11.8321H72.8351C72.922 12.5528 73.2676 13.2201 73.8107 13.716C74.5832 14.4362 75.645 14.7674 76.8344 14.7674C78.1118 14.7674 79.2814 14.452 80.0378 13.716C80.3059 13.4537 80.516 13.1407 80.6554 12.7963C80.7948 12.4518 80.8603 12.0831 80.8481 11.713C80.8481 10.2725 79.7701 9.35952 78.2915 9.1317C77.3734 8.99151 77.1398 8.97399 76.2936 8.86884C75.7906 8.79875 75.2156 8.60423 75.2156 7.95585C75.221 7.74283 75.2926 7.53643 75.4209 7.364C75.5493 7.19157 75.7283 7.06124 75.9343 6.99027C76.2444 6.87685 76.5757 6.82906 76.9063 6.85009C77.3534 6.83794 77.7893 6.98777 78.1298 7.27066C78.3656 7.49879 78.5014 7.80723 78.5088 8.13109" fill="white"/> +</g> +<defs> +<clipPath id="clip0_7225_43052"> +<rect width="80" height="17" fill="white" transform="translate(0.848022)"/> +</clipPath> +</defs> +</svg> From b6402b0b3e9509db052db16eb9ea4905ac188715 Mon Sep 17 00:00:00 2001 From: Troy Howard <thoward37@gmail.com> Date: Wed, 4 Jun 2025 03:13:06 -0500 Subject: [PATCH 2/3] fix harness doc formatting --- .../continuous-delivery/harness.md | 73 ++++++++++--------- 1 file changed, 38 insertions(+), 35 deletions(-) diff --git a/content/docs/iac/using-pulumi/continuous-delivery/harness.md b/content/docs/iac/using-pulumi/continuous-delivery/harness.md index 8c79bc1a4848..63be7381391b 100644 --- a/content/docs/iac/using-pulumi/continuous-delivery/harness.md +++ b/content/docs/iac/using-pulumi/continuous-delivery/harness.md @@ -19,8 +19,7 @@ Pulumi doesn't require any particular arrangement of stacks or workflow to work ## Prerequisites - An account on [https://app.pulumi.com](https://app.pulumi.com) -- The latest Pulumi CLI - - [Installation instructions](/docs/install/) +- The latest [Pulumi CLI](/docs/install/) - A Harness account and access to Harness CI/CD - A git repository connected to your Harness project - [Pulumi Harness provider](/registry/packages/harness/) (optional, for managing Harness resources) @@ -56,7 +55,7 @@ values: AWS_REGION: ${aws.AWS_REGION} ``` -2. **Configure your Harness pipeline** to use ESC: +1. **Configure your Harness pipeline** to use ESC: ```yaml - step: @@ -69,10 +68,9 @@ values: # Install and use ESC CLI to inject environment variables curl -fsSL https://get.pulumi.com/esc/install.sh | sh export PATH=$PATH:$HOME/.pulumi/bin - # Open ESC environment and export variables eval "$(esc open your-org/your-environment --format shell)" - + # These variables are now available for subsequent steps echo "Environment loaded successfully" envVariables: @@ -126,7 +124,6 @@ pipeline: # Install Pulumi CLI curl -fsSL https://get.pulumi.com | sh export PATH=$PATH:$HOME/.pulumi/bin - # Install language-specific dependencies case "<+pipeline.variables.language>" in "typescript"|"javascript") @@ -151,13 +148,12 @@ pipeline: command: | export PATH=$PATH:$HOME/.pulumi/bin cd <+pipeline.variables.workingDirectory> - + # Login to Pulumi pulumi login - + # Select the stack pulumi stack select <+pipeline.variables.stackName> - # Run preview pulumi preview envVariables: @@ -193,7 +189,6 @@ pipeline: # Install Pulumi CLI curl -fsSL https://get.pulumi.com | sh export PATH=$PATH:$HOME/.pulumi/bin - # Install language-specific dependencies case "<+pipeline.variables.language>" in "typescript"|"javascript") @@ -232,13 +227,12 @@ pipeline: command: | export PATH=$PATH:$HOME/.pulumi/bin cd <+pipeline.variables.workingDirectory> - # Login to Pulumi pulumi login - + # Select the stack pulumi stack select <+pipeline.variables.stackName> - + # Deploy infrastructure pulumi up --yes envVariables: @@ -279,6 +273,7 @@ You can use Harness to deploy applications while leveraging Pulumi to manage the 3. **Integration through stack outputs**: Pulumi stack outputs provide connection details to Harness deployments Example workflow: + ```bash # Infrastructure pipeline (Pulumi) pulumi up --stack production-infra @@ -541,12 +536,12 @@ pipeline: command: | # Use Pulumi template with dynamic configuration pulumi new aws-typescript --name <+pipeline.variables.applicationName> - + # Configure based on template inputs pulumi config set aws:region us-east-1 pulumi config set instanceSize <+pipeline.variables.instanceSize> pulumi config set environment <+pipeline.variables.environment> - + # Deploy infrastructure pulumi up --yes ``` @@ -558,6 +553,7 @@ pipeline: Pulumi excels at managing different environments with varying infrastructure needs. You can structure your infrastructure to handle the unique requirements of development, staging, and production environments: #### Development Environment + - **Smaller resource allocations**: Use smaller instance sizes and fewer replicas - **Relaxed security**: Allow broader access for debugging and testing - **Cost optimization**: Use spot instances or scaled-down services @@ -567,7 +563,7 @@ Pulumi excels at managing different environments with varying infrastructure nee const config = new pulumi.Config(); const environment = config.require("environment"); -const instanceType = environment === "dev" ? "t3.micro" : +const instanceType = environment === "dev" ? "t3.micro" : environment === "staging" ? "t3.small" : "t3.large"; const cluster = new aws.ecs.Cluster("app-cluster", { @@ -576,12 +572,14 @@ const cluster = new aws.ecs.Cluster("app-cluster", { ``` #### Staging Environment + - **Production-like configuration**: Mirror production settings for accurate testing - **Data isolation**: Use production-sized databases with test data - **Security testing**: Enable security scanning and compliance checks - **Performance testing**: Scale to handle load testing scenarios #### Production Environment + - **High availability**: Multi-zone deployments with redundancy - **Enhanced security**: Strict network policies and encryption - **Monitoring and alerting**: Comprehensive observability stack @@ -592,6 +590,7 @@ const cluster = new aws.ecs.Cluster("app-cluster", { Harness approval gates work particularly well with Pulumi workflows. You can implement different approval strategies: #### Infrastructure Change Approvals + Use approval gates specifically for infrastructure changes that require review: ```yaml @@ -619,6 +618,7 @@ Use approval gates specifically for infrastructure changes that require review: ``` #### Environment-Specific Approvals + Different environments can have different approval requirements: ```yaml @@ -638,6 +638,7 @@ Different environments can have different approval requirements: ``` #### Application Deployment Gates + Coordinate infrastructure and application deployments with sequential approval gates: ```yaml @@ -689,38 +690,40 @@ For complex environments with multiple stacks, you can configure your Harness pi ## Best Practices -1. **Use Secrets Management**: Prefer Pulumi ESC for centralized secrets management, with Harness secrets as a secondary option for platform-specific needs. +Following these best practices will help ensure reliable, secure, and maintainable infrastructure deployments with Harness and Pulumi: -2. **Environment Configuration**: Use different Pulumi stacks and ESC environments for each deployment target (dev/staging/production). +- **Use Secrets Management**: Prefer Pulumi ESC for centralized secrets management, with Harness secrets as a secondary option for platform-specific needs. -3. **Resource Tagging**: Tag your infrastructure resources with environment and ownership information for better cost management and organization. +- **Environment Configuration**: Use different Pulumi stacks and ESC environments for each deployment target (dev/staging/production). -4. **Pipeline Validation**: Always run `pulumi preview` before `pulumi up` to review changes. +- **Resource Tagging**: Tag your infrastructure resources with environment and ownership information for better cost management and organization. -5. **Approval Gates**: Implement appropriate approval gates based on environment criticality and change scope. +- **Pipeline Validation**: Always run `pulumi preview` before `pulumi up` to review changes. -6. **Rollback Strategy**: Implement proper rollback mechanisms using Pulumi's stack history: +- **Approval Gates**: Implement appropriate approval gates based on environment criticality and change scope. -```bash -# Rollback to previous deployment -pulumi stack history -pulumi stack export --version <previous-version> > previous-state.json -pulumi stack import previous-state.json -``` +- **Rollback Strategy**: Implement proper rollback mechanisms using Pulumi's stack history: + + ```bash + # Rollback to previous deployment + pulumi stack history + pulumi stack export --version <previous-version> > previous-state.json + pulumi stack import previous-state.json + ``` -7. **IDP Integration**: When using Harness as an IDP, provide templates and self-service capabilities that abstract infrastructure complexity from developers. +- **IDP Integration**: When using Harness as an IDP, provide templates and self-service capabilities that abstract infrastructure complexity from developers. ## Troubleshooting -Common issues and solutions: +When integrating Harness with Pulumi, you may encounter some common issues. Here are solutions to the most frequently encountered problems: -1. **Authentication Failures**: Ensure all required secrets are properly configured in Harness or Pulumi ESC. +- **Authentication Failures**: Ensure all required secrets are properly configured in Harness or Pulumi ESC. -2. **Stack Not Found**: Verify stack names and ensure stacks exist in the Pulumi Cloud. +- **Stack Not Found**: Verify stack names and ensure stacks exist in the Pulumi Cloud. -3. **Resource Conflicts**: Use `pulumi refresh` to sync state with actual cloud resources. +- **Resource Conflicts**: Use `pulumi refresh` to sync state with actual cloud resources. -4. **Pipeline Timeouts**: Increase timeout values for long-running infrastructure deployments. +- **Pipeline Timeouts**: Increase timeout values for long-running infrastructure deployments. For additional troubleshooting, see our [CI/CD troubleshooting guide](/docs/iac/using-pulumi/continuous-delivery/troubleshooting-guide). @@ -730,4 +733,4 @@ For additional troubleshooting, see our [CI/CD troubleshooting guide](/docs/iac/ - Learn about [Pulumi ESC](/docs/esc/) for advanced secrets and configuration management - Check out [Pulumi Deployments](/docs/pulumi-cloud/deployments/) for additional CI/CD capabilities - Review [Harness CI/CD documentation](https://docs.harness.io/category/zgffarnh1m-ci-category) for platform-specific features -- Explore [Harness IDP documentation](https://docs.harness.io/docs/internal-developer-portal) for internal developer platform capabilities \ No newline at end of file +- Explore [Harness IDP documentation](https://docs.harness.io/docs/internal-developer-portal) for internal developer platform capabilities From 05621a203e59f1b5175d7224cba4ca5c5d264a6a Mon Sep 17 00:00:00 2001 From: Troy Howard <thoward37@gmail.com> Date: Wed, 4 Jun 2025 03:20:52 -0500 Subject: [PATCH 3/3] use a larger version of the logo --- static/logos/tech/ci-cd/harness.svg | 115 +++++++++++++++++++++++++--- 1 file changed, 105 insertions(+), 10 deletions(-) diff --git a/static/logos/tech/ci-cd/harness.svg b/static/logos/tech/ci-cd/harness.svg index 25ccf1fcab0d..0972fa8f352d 100644 --- a/static/logos/tech/ci-cd/harness.svg +++ b/static/logos/tech/ci-cd/harness.svg @@ -1,11 +1,106 @@ -<svg width="81" height="17" viewBox="0 0 81 17" fill="none" xmlns="http://www.w3.org/2000/svg"> -<g clip-path="url(#clip0_7225_43052)"> -<path d="M16.9673 5.56561L12.5764 1.27749C12.0564 0.798006 11.437 0.432892 10.76 0.20678C9.2598 -0.280386 7.76681 0.0998812 6.55768 1.27749L2.15595 5.56561C1.66437 6.07281 1.29004 6.67696 1.05822 7.33728C0.55696 8.80053 0.946827 10.2568 2.15595 11.4344L6.55229 15.7225C7.07146 16.2022 7.69031 16.5673 8.36688 16.7932C8.77674 16.9284 9.20624 16.9982 9.63888 17C10.6935 17 11.7032 16.5654 12.5692 15.7225L16.9637 11.4344C17.4559 10.9274 17.8309 10.3232 18.0632 9.66271C18.5627 8.19946 18.1728 6.74497 16.9637 5.56561H16.9673ZM9.8994 2.52169C10.2315 2.62555 10.5376 2.7963 10.7977 3.02288L12.0967 4.29162L9.56343 6.76074L7.03019 4.28986L8.33633 3.01412C8.68667 2.67415 9.18075 2.31316 9.90299 2.51994L9.8994 2.52169ZM3.43515 8.16792C3.54196 7.84374 3.71766 7.54518 3.95078 7.29172L5.24974 6.02473L7.78298 8.49561L5.24794 10.9665L3.9418 9.69075C3.59146 9.35078 3.22315 8.86888 3.43335 8.16441L3.43515 8.16792ZM9.22386 14.473C8.89133 14.3701 8.5851 14.1993 8.32555 13.9719L7.03019 12.7189L9.56343 10.2463L12.0967 12.7171L10.7905 13.9929C10.4402 14.3328 9.9479 14.6938 9.22386 14.4871V14.473ZM15.6917 8.83908C15.5849 9.1629 15.4099 9.46135 15.1779 9.71528L13.8789 10.9665L11.3457 8.49561L13.8789 6.02473L15.1851 7.29873C15.5354 7.63869 15.9037 8.1206 15.6935 8.82506" fill="#00ADE4"/> -<path d="M26.4481 14.5378H28.7173V8.39569C28.7173 6.50135 27.5369 5.10295 25.5229 5.10295C24.5419 5.10295 23.4909 5.52702 22.9447 6.30684V1.75061H20.6774V14.5326H22.9447V9.68722C22.9447 8.55517 23.5268 7.13923 24.8869 7.13923C26.0852 7.13923 26.4481 7.79287 26.4481 8.85658V14.5378ZM35.6109 10.9051C35.6109 12.2562 34.621 12.994 33.2178 12.994C32.5153 12.994 31.8847 12.5559 31.8847 11.8532C31.8847 11.1154 32.5512 10.7124 33.2358 10.6598L35.6109 10.4846V10.9051ZM37.5009 14.6798C37.8882 14.6921 38.2723 14.6077 38.6166 14.4345V12.8187C38.5224 12.8404 38.426 12.8521 38.3292 12.8538C37.9519 12.8538 37.8082 12.6961 37.8082 12.2737V8.88637C37.8365 8.26073 37.7445 7.63545 37.5369 7.04284C36.9979 5.67247 35.6289 5.1818 34.0281 5.1818C31.9386 5.1818 30.2641 6.0948 30.1384 8.14861H32.3177C32.3716 7.30571 32.9824 6.85009 34.0281 6.85009C35.3055 6.85009 35.6109 7.42837 35.6109 8.2888V8.85132L32.8549 9.03883C31.0726 9.16149 29.6874 10.1621 29.6874 11.9005C29.6874 13.3935 30.8391 14.7622 33.0723 14.7622C34.4036 14.7622 35.4833 14.1313 35.9163 13.3935C35.9882 14.0787 36.5272 14.6745 37.4991 14.6745L37.5009 14.6798ZM44.5707 7.35302C44.6908 7.35388 44.8107 7.36148 44.93 7.3758V5.30797C44.833 5.30797 44.7359 5.28695 44.6407 5.28695C43.5412 5.28695 42.4255 5.72505 41.9943 6.77824L41.7949 5.40962H39.8851V14.5396H42.1542V9.93956C42.1542 8.46404 42.9824 7.35828 44.5653 7.35828L44.5707 7.35302ZM51.6709 14.5431H53.9221V8.44652C53.9221 6.55042 52.7507 5.1818 50.7528 5.1818C49.6749 5.1818 48.5574 5.6199 47.9986 6.58372L47.8369 5.40786H45.9523V14.5378H48.2016V10.8175C48.2016 10.0447 48.1837 9.09666 48.5088 8.37642C48.8143 7.70876 49.3371 7.21808 50.1258 7.21808C51.3134 7.21808 51.6727 7.86822 51.6727 8.93894L51.6709 14.5431ZM61.3098 9.06511H57.2638C57.2539 8.55035 57.4258 8.04792 57.7507 7.64217C57.9378 7.41436 58.1769 7.23234 58.4489 7.11064C58.7209 6.98894 59.0183 6.93092 59.3173 6.94121C59.5787 6.92759 59.8401 6.96731 60.0848 7.05783C60.3295 7.14836 60.5521 7.28769 60.7385 7.46693C61.0978 7.85421 61.2972 8.37992 61.3152 9.06511H61.3098ZM63.5645 10.0482C63.6005 8.9074 63.4388 7.87173 62.7543 6.86936C61.9817 5.72855 60.7205 5.18531 59.3407 5.18531C58.7878 5.16957 58.2374 5.2642 57.7233 5.46339C57.2092 5.66258 56.7422 5.96212 56.3511 6.34364C55.4528 7.23911 55.0018 8.53764 55.0018 9.99563C55.0018 11.4887 55.5049 12.7697 56.4391 13.6476C56.8298 14.0174 57.2924 14.3073 57.7997 14.5002C58.3069 14.6931 58.8486 14.7852 59.3928 14.7709C60.5804 14.7709 61.75 14.4029 62.5423 13.4899C62.9016 13.0676 63.2807 12.3491 63.3346 11.8041H61.1786C61.1029 12.0968 60.9471 12.364 60.7277 12.5769C60.4043 12.8923 60.009 13.015 59.3604 13.015C58.8405 13.0133 58.3422 12.8119 57.9735 12.4542C57.7404 12.2169 57.5595 11.9356 57.4418 11.6276C57.3241 11.3197 57.2721 10.9915 57.2889 10.6633H63.5466C63.5466 10.4688 63.5645 10.0482 63.5645 10.0482ZM66.5865 7.95935C66.5918 7.74634 66.6634 7.53994 66.7918 7.3675C66.9201 7.19507 67.0991 7.06474 67.3051 6.99378C67.6152 6.88035 67.9466 6.83257 68.2771 6.85359C68.7242 6.84144 69.1601 6.99127 69.5006 7.27416C69.7359 7.50247 69.8711 7.81094 69.8779 8.13459H72.0212C71.9943 7.42971 71.699 6.75992 71.193 6.25602C70.5103 5.53403 69.3766 5.18355 68.2609 5.18355C67.0895 5.18355 66.105 5.51651 65.4169 6.09655C65.1096 6.34678 64.8643 6.66143 64.6991 7.01705C64.5339 7.37266 64.4531 7.76006 64.4629 8.15036C64.4629 9.30869 65.327 10.3268 66.6044 10.5914C67.4327 10.7667 68.3687 10.8193 69.197 10.9419C69.7719 11.0295 70.133 11.38 70.133 11.9075C70.133 12.9081 68.9814 13.0658 68.225 13.0658C67.5764 13.0658 67.1632 12.9432 66.8021 12.6628C66.5532 12.4454 66.3863 12.1529 66.3278 11.8321H64.2077C64.2948 12.5523 64.6396 13.2195 65.1815 13.716C65.9558 14.4362 67.0177 14.7674 68.207 14.7674C69.4844 14.7674 70.654 14.452 71.4104 13.716C71.6791 13.454 71.89 13.1412 72.03 12.7967C72.1699 12.4522 72.2361 12.0834 72.2243 11.713C72.2243 10.2725 71.1463 9.35952 69.6677 9.1317C68.7496 8.99151 68.516 8.97399 67.6698 8.86884C67.1668 8.79875 66.5919 8.60423 66.5919 7.95585L66.5865 7.95935ZM78.5142 8.13109H80.6504C80.6235 7.42621 80.3282 6.75642 79.8222 6.25252C79.1377 5.53403 78.004 5.18355 76.8955 5.18355C75.7259 5.18355 74.7395 5.51651 74.0514 6.09655C73.7442 6.34678 73.4988 6.66143 73.3336 7.01705C73.1684 7.37266 73.0877 7.76006 73.0974 8.15036C73.0974 9.30869 73.9616 10.3268 75.239 10.5914C76.0672 10.7667 77.0033 10.8193 77.8315 10.9419C78.4064 11.0295 78.7676 11.38 78.7676 11.9075C78.7676 12.9081 77.6141 13.0658 76.8596 13.0658C76.211 13.0658 75.7978 12.9432 75.4366 12.6628C75.1878 12.4454 75.0208 12.1529 74.9623 11.8321H72.8351C72.922 12.5528 73.2676 13.2201 73.8107 13.716C74.5832 14.4362 75.645 14.7674 76.8344 14.7674C78.1118 14.7674 79.2814 14.452 80.0378 13.716C80.3059 13.4537 80.516 13.1407 80.6554 12.7963C80.7948 12.4518 80.8603 12.0831 80.8481 11.713C80.8481 10.2725 79.7701 9.35952 78.2915 9.1317C77.3734 8.99151 77.1398 8.97399 76.2936 8.86884C75.7906 8.79875 75.2156 8.60423 75.2156 7.95585C75.221 7.74283 75.2926 7.53643 75.4209 7.364C75.5493 7.19157 75.7283 7.06124 75.9343 6.99027C76.2444 6.87685 76.5757 6.82906 76.9063 6.85009C77.3534 6.83794 77.7893 6.98777 78.1298 7.27066C78.3656 7.49879 78.5014 7.80723 78.5088 8.13109" fill="white"/> -</g> -<defs> -<clipPath id="clip0_7225_43052"> -<rect width="80" height="17" fill="white" transform="translate(0.848022)"/> -</clipPath> -</defs> +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="200px" height="200px" viewBox="0 0 200 200" enable-background="new 0 0 200 200" xml:space="preserve"> <image id="image0" width="200" height="200" x="0" y="0" + href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAMAAACahl6sAAAABGdBTUEAALGPC/xhBQAAACBjSFJN +AAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAC91BMVEUAAAAAreUAreUAreUA +reUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUA +reUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUA +reUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUA +reUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUA +reUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUA +reUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUA +reUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUA +reUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUA +reUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUA +reUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUA +reUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUA +reUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUA +reUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUAreUA +reX///9DCht9AAAA+3RSTlMAAAgeOlyBo8DW5Ozu5dfCpoZiPyMMAQ4xYZW+2/n++vDfxaFwQBcE +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" /> </svg>