├── .github ├── CONTRIBUTING.md ├── ISSUE_TEMPLATE │ ├── config.yml │ ├── issue-bug.yml │ └── issue-enhance.yml ├── PULL_REQUEST_TEMPLATE.md └── TEMPLATE-README.md ├── .gitignore ├── CODEOWNERS ├── LICENSE ├── NOTICE ├── README.md ├── client.go ├── client_test.go ├── containermetrics ├── cached_container_metric.go ├── cpu_spike_reporter.go ├── metrics_suite_test.go ├── package.go ├── reporters_runner.go ├── reporters_runner_test.go └── stats_reporter.go ├── depot ├── containerstore │ ├── containerreaper.go │ ├── containerstore.go │ ├── containerstore_suite_test.go │ ├── containerstore_test.go │ ├── containerstorefakes │ │ ├── fake_bindmounter.go │ │ ├── fake_container_info_provider.go │ │ ├── fake_containerstore.go │ │ ├── fake_cred_handler.go │ │ ├── fake_cred_manager.go │ │ ├── fake_fs_operations.go │ │ ├── fake_garden_client_factory.go │ │ ├── fake_log_manager.go │ │ ├── fake_proxymanager.go │ │ ├── fake_volume_mounted_files_handler.go │ │ └── package.go │ ├── credmanager.go │ ├── credmanager_test.go │ ├── dependencymanager.go │ ├── dependencymanager_test.go │ ├── garden_client_factory.go │ ├── helpers.go │ ├── instance_identity_handler.go │ ├── instance_identity_handler_test.go │ ├── log_manager.go │ ├── nodemap.go │ ├── package.go │ ├── proxy_config_handler.go │ ├── proxy_config_handler_test.go │ ├── registrypruner.go │ ├── storenode.go │ ├── volume_mounted_files_handler.go │ └── volume_mounted_files_handler_test.go ├── depot.go ├── depot_suite_test.go ├── depot_test.go ├── event │ ├── fakes │ │ ├── fake_hub.go │ │ └── package.go │ ├── hub.go │ └── package.go ├── log_streamer │ ├── buffer_streamer.go │ ├── buffer_streamer_test.go │ ├── concurrent_buffer.go │ ├── concurrent_buffer_test.go │ ├── fake_log_streamer │ │ ├── constructor.go │ │ ├── fake_log_streamer.go │ │ └── package.go │ ├── log_rate_limiter.go │ ├── log_rate_limiter_test.go │ ├── log_streamer.go │ ├── log_streamer_suite_test.go │ ├── log_streamer_test.go │ ├── noop_streamer.go │ ├── package.go │ └── stream_destination.go ├── metrics │ ├── metrics_suite_test.go │ ├── package.go │ ├── reporter.go │ └── reporter_test.go ├── package.go ├── steps │ ├── background_step.go │ ├── background_step_test.go │ ├── codependent_step.go │ ├── codependent_step_test.go │ ├── consistently_succeeds_step.go │ ├── consistently_succeeds_step_test.go │ ├── download_step.go │ ├── download_step_test.go │ ├── emit_check_failure_metric_step.go │ ├── emit_check_failure_metric_step_test.go │ ├── emit_progress_step.go │ ├── emit_progress_step_test.go │ ├── emittable_error.go │ ├── emittable_error_test.go │ ├── errors.go │ ├── eventually_succeeds_step.go │ ├── eventually_succeeds_step_test.go │ ├── health_check_step.go │ ├── health_check_step_test.go │ ├── monitor_step.go │ ├── monitor_step_test.go │ ├── output_wrapper_step.go │ ├── output_wrapper_step_test.go │ ├── package.go │ ├── parallel_step.go │ ├── parallel_step_test.go │ ├── readiness_health_check_step.go │ ├── readiness_health_check_step_test.go │ ├── run_step.go │ ├── run_step_test.go │ ├── serial_step.go │ ├── serial_step_test.go │ ├── steps_suite_test.go │ ├── throttle_step.go │ ├── throttle_step_test.go │ ├── timed_step.go │ ├── timed_step_test.go │ ├── timeout_step.go │ ├── timeout_step_test.go │ ├── try_step.go │ ├── try_step_test.go │ ├── upload_step.go │ └── upload_step_test.go ├── transformer │ ├── faketransformer │ │ ├── fake_transformer.go │ │ └── package.go │ ├── package.go │ ├── transformer.go │ ├── transformer_suite_test.go │ ├── transformer_test.go │ ├── transformer_unix.go │ └── transformer_windows.go └── uploader │ ├── fake_uploader │ ├── fake_uploader.go │ └── package.go │ ├── fixtures │ ├── correct │ │ ├── client.crt │ │ ├── client.csr │ │ ├── client.key │ │ ├── server-ca.crl │ │ ├── server-ca.crt │ │ ├── server-ca.key │ │ ├── server.crt │ │ ├── server.csr │ │ └── server.key │ ├── incorrect │ │ ├── client.crt │ │ ├── client.csr │ │ ├── client.key │ │ ├── server-ca.crl │ │ ├── server-ca.crt │ │ └── server-ca.key │ └── regenerate-certs.sh │ ├── package.go │ ├── uploader.go │ ├── uploader_suite_test.go │ └── uploader_test.go ├── errors.go ├── executor_suite_test.go ├── fakes ├── fake_client.go ├── fake_event_source.go ├── fake_garden_client.go └── package.go ├── gardenhealth ├── README.go ├── checker.go ├── checker_test.go ├── fakegardenhealth │ ├── fake_checker.go │ └── package.go ├── gardenhealth_suite_test.go ├── package.go ├── runner.go └── runner_test.go ├── guidgen ├── fakeguidgen │ ├── fake_generator.go │ └── package.go ├── generator.go └── package.go ├── initializer ├── configuration │ ├── configuration.go │ ├── configuration_suite_test.go │ ├── configuration_test.go │ ├── configurationfakes │ │ ├── fake_rootfssizer.go │ │ └── package.go │ └── package.go ├── fakes │ ├── fake_cert_pool_retriever.go │ └── package.go ├── fixtures │ ├── ca-certs │ ├── ca-certs-empty │ ├── ca-certs-invalid │ ├── ca-certs-with-spaces.crt │ ├── downloader │ │ ├── ca.crl │ │ ├── ca.crt │ │ ├── ca.key │ │ ├── client.crt │ │ ├── client.csr │ │ └── client.key │ ├── instance-id │ │ ├── ca.crl │ │ ├── ca.crt │ │ ├── ca.key │ │ ├── invalid.crt │ │ ├── invalid.key │ │ ├── multiple-ca.crt │ │ ├── multiple-ca.csr │ │ ├── multiple-ca.key │ │ ├── non-pem.crt │ │ └── non-pem.key │ ├── regenerate-certs.sh │ └── systemcerts │ │ ├── extra-ca.crl │ │ ├── extra-ca.crt │ │ └── extra-ca.key ├── initializer.go ├── initializer_suite_test.go ├── initializer_test.go └── package.go ├── package.go ├── resource_converters.go ├── resources.go └── resources_test.go /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Contributor License Agreement 2 | --------------- 3 | 4 | Follow these steps to make a contribution to any of our open source repositories: 5 | 6 | 1. Ensure that you have completed our CLA Agreement for [individuals](https://www.cloudfoundry.org/wp-content/uploads/2015/07/CFF_Individual_CLA.pdf) or [corporations](https://www.cloudfoundry.org/wp-content/uploads/2015/07/CFF_Corporate_CLA.pdf). 7 | 8 | 1. Set your name and email (these should match the information on your submitted CLA) 9 | ``` 10 | git config --global user.name "Firstname Lastname" 11 | git config --global user.email "your_email@example.com" 12 | ``` 13 | 14 | 1. All contributions must be sent using GitHub pull requests as they create a nice audit trail and structured approach. 15 | 16 | The originating github user has to either have a github id on-file with the list of approved users that have signed 17 | the CLA or they can be a public "member" of a GitHub organization for a group that has signed the corporate CLA. 18 | This enables the corporations to manage their users themselves instead of having to tell us when someone joins/leaves an organization. By removing a user from an organization's GitHub account, their new contributions are no longer approved because they are no longer covered under a CLA. 19 | 20 | If a contribution is deemed to be covered by an existing CLA, then it is analyzed for engineering quality and product 21 | fit before merging it. 22 | 23 | If a contribution is not covered by the CLA, then the automated CLA system notifies the submitter politely that we 24 | cannot identify their CLA and ask them to sign either an individual or corporate CLA. This happens automatically as a 25 | comment on pull requests. 26 | 27 | When the project receives a new CLA, it is recorded in the project records, the CLA is added to the database for the 28 | automated system uses, then we manually make the Pull Request as having a CLA on-file. 29 | 30 | 31 | Initial Setup 32 | --------------- 33 | - Install docker 34 | 35 | - Add required directories 36 | 37 | ```bash 38 | # create parent directory 39 | mkdir -p ~/workspace 40 | cd ~/workspace 41 | 42 | # clone ci 43 | git clone https://github.com/cloudfoundry/wg-app-platform-runtime-ci.git 44 | 45 | # clone repo 46 | git clone https://github.com/cloudfoundry/diego-release.git --recursive 47 | cd diego-release 48 | ``` 49 | 50 | Running Tests 51 | --------------- 52 | 53 | > [!TIP] 54 | > Running tests for this repo requires a DB flavor. The following scripts will default to mysql DB. Set DB environment variable for alternate DBs. Valid Options: mysql-8.0(or mysql),postgres 55 | 56 | - `./scripts/create-docker-container.bash`: This will create a docker container with appropriate mounts. This 57 | script can be used for interactive development with a long running container. 58 | - `./scripts/test-in-docker.bash`: Create docker container and run all tests and setup in a single script. 59 | - `./scripts/test-in-docker.bash `: For running tests under a specific package and/or sub-package 60 | 61 | When inside docker container: 62 | 63 | - `/repo/scripts/docker/build-binaries.bash`: (REQUIRED) This will build required binaries for running tests. 64 | - `/repo/scripts/docker/test.bash`: This will run all tests in this repo. 65 | - `/repo/scripts/docker/test.bash `: This will only run a package's tests 66 | - `/repo/scripts/docker/test.bash `: This will only run sub-package tests for package 67 | - `/repo/scripts/docker/tests-template.bash`: This will test bosh-spec templates. 68 | - `/repo/scripts/docker/lint.bash`: This will run required linters. 69 | 70 | > [!IMPORTANT] 71 | > If you are about to submit a PR, please make sure to run `./scripts/test-in-docker.bash` for MySQL and Postgres to ensure everything is tested in clean container. If you are developing, you can create create a docker container first, then the only required script to run before testing your specific component is `build-binaries.bash`. 72 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: CloudFoundry slack 4 | url: https://cloudfoundry.slack.com 5 | about: For help or questions about this component, you can reach the maintainers on Slack 6 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/issue-bug.yml: -------------------------------------------------------------------------------- 1 | name: Bug 2 | description: Report a defect, such as a bug or regression. 3 | title: "Start the title with a verb (e.g. Change header styles). Use the imperative mood in the title (e.g. Fix, not Fixed or Fixes header styles)" 4 | labels: 5 | - bug 6 | body: 7 | - type: textarea 8 | id: current 9 | attributes: 10 | label: Current behavior 11 | validations: 12 | required: true 13 | - type: markdown 14 | id: current_md 15 | attributes: 16 | value: | 17 | - Explain, in detail, what the current state of the world is 18 | - Include code snippets, log output, and analysis as necessary to explain the whole problem 19 | - Include links to logs, GitHub issues, slack conversations, etc.. to tell us where the problem came from 20 | - Steps to reproduce 21 | - type: textarea 22 | id: desired 23 | attributes: 24 | label: Desired behavior 25 | validations: 26 | required: true 27 | - type: markdown 28 | id: desired_md 29 | attributes: 30 | value: | 31 | - Describe how the problem should be fixed 32 | - Does this require a new bosh release? 33 | - Does it require configuration changes in cf-deployment? 34 | - Do we need to have a special release note? 35 | - Do we need to update repo documentation? 36 | - type: input 37 | id: version 38 | attributes: 39 | label: Affected Version 40 | description: Please enter the version 41 | validations: 42 | required: true 43 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/issue-enhance.yml: -------------------------------------------------------------------------------- 1 | name: Enhance 2 | description: Propose an enhancement or new feature. 3 | title: "Start the title with a verb (e.g. Change header styles). Use the imperative mood in the title (e.g. Fix, not Fixed or Fixes header styles)" 4 | labels: 5 | - enhancement 6 | body: 7 | - type: textarea 8 | id: change 9 | attributes: 10 | label: Proposed Change 11 | validations: 12 | required: true 13 | - type: markdown 14 | id: change_md 15 | attributes: 16 | value: | 17 | Briefly explain why this feature is necessary in the following format 18 | 19 | **As a** *developer/operator/whatever* 20 | **I want** *this ability to do X* 21 | **So that** *I can do Y* 22 | 23 | - Provide details of where this request is coming from including links, GitHub Issues, etc.. 24 | - Provide details of prior work (if applicable) including links to commits, github issues, etc... 25 | - type: textarea 26 | id: acceptance 27 | attributes: 28 | label: Acceptance criteria 29 | validations: 30 | required: true 31 | - type: markdown 32 | id: acceptance_md 33 | attributes: 34 | value: | 35 | Detail the exact work that is required to accept this story in the following format 36 | 37 | **Scenario:** *describe scenario* 38 | **Given** *I have some sort of configuration* 39 | **When** *I do X* 40 | **And** *do Y* 41 | **Then** *I see the desired behavior* 42 | 43 | - type: textarea 44 | id: related 45 | attributes: 46 | label: Related links 47 | description: Please list related links for this issue 48 | placeholder: | 49 | - [ ] code.cloudfoundry.org/bbs for links 50 | - [x] cloudfoundry/rep#123 for issues/prs 51 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | - [ ] Read the [Contributing document](../blob/-/.github/CONTRIBUTING.md). 2 | 3 | Summary 4 | --------------- 5 | 10 | 11 | 12 | Backward Compatibility 13 | --------------- 14 | Breaking Change? **Yes/No** 15 | 22 | -------------------------------------------------------------------------------- /.github/TEMPLATE-README.md: -------------------------------------------------------------------------------- 1 | 2 | > [!IMPORTANT] 3 | > Content in this directory is managed by the CI task `sync-dot-github-dir`. 4 | 5 | Changing templates 6 | --------------- 7 | These templates are synced from [these shared templates](https://github.com/cloudfoundry/wg-app-platform-runtime-ci/tree/main/shared/github). 8 | Each pipeline will contain a `sync-dot-github-dir-*` job for updating the content of these files. 9 | If you would like to modify these, please change them in the shared group. 10 | It's also possible to override the templates on pipeline's parent directory by introducing a custom 11 | template in `$PARENT_TEMPLATE_DIR/github/FILENAME` or `$PARENT_TEMPLATE_DIR/github/REPO_NAME/FILENAME` in CI repo 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.test 2 | *.swp 3 | .DS_Store 4 | .idea 5 | *.coverprofile 6 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @cloudfoundry/wg-app-runtime-platform-diego-approvers 2 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015-Present CloudFoundry.org Foundation, Inc. All Rights Reserved. 2 | 3 | This project contains software that is Copyright (c) 2014-2015 Pivotal Software, Inc. 4 | 5 | Licensed under the Apache License, Version 2.0 (the "License"); 6 | you may not use this file except in compliance with the License. 7 | You may obtain a copy of the License at 8 | 9 | http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | Unless required by applicable law or agreed to in writing, software 12 | distributed under the License is distributed on an "AS IS" BASIS, 13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | See the License for the specific language governing permissions and 15 | limitations under the License. 16 | 17 | This project may include a number of subcomponents with separate 18 | copyright notices and license terms. Your use of these subcomponents 19 | is subject to the terms and conditions of each subcomponent's license, 20 | as noted in the LICENSE file. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Executor 2 | 3 | [![Go Report 4 | Card](https://goreportcard.com/badge/code.cloudfoundry.org/executor)](https://goreportcard.com/report/code.cloudfoundry.org/executor) 5 | [![Go 6 | Reference](https://pkg.go.dev/badge/code.cloudfoundry.org/executor.svg)](https://pkg.go.dev/code.cloudfoundry.org/executor) 7 | 8 | Let me run that for you. 9 | 10 | Executor is a logical process running inside the 11 | [Rep](https://github.com/cloudfoundry/rep) that: \* manages container 12 | allocations against resource constraints on the Cell, such as memory and 13 | disk space \* implements the actions detailed in the API documentation 14 | \* streams stdout and stderr from container processes to the 15 | metron-agent running on the Cell, which in turn forwards to the 16 | Loggregator system \* periodically collects container metrics and emits 17 | them to Loggregator 18 | 19 | > \[!NOTE\] 20 | > 21 | > This repository should be imported as 22 | > `code.cloudfoundry.org/executor`. 23 | 24 | # Contributing 25 | 26 | See the [Contributing.md](./.github/CONTRIBUTING.md) for more 27 | information on how to contribute. 28 | 29 | # Working Group Charter 30 | 31 | This repository is maintained by [App Runtime 32 | Platform](https://github.com/cloudfoundry/community/blob/main/toc/working-groups/app-runtime-platform.md) 33 | under `Diego` area. 34 | 35 | > \[!IMPORTANT\] 36 | > 37 | > Content in this file is managed by the [CI task 38 | > `sync-readme`](https://github.com/cloudfoundry/wg-app-platform-runtime-ci/blob/main/shared/tasks/sync-readme/metadata.yml) 39 | > and is generated by CI following a convention. 40 | -------------------------------------------------------------------------------- /client.go: -------------------------------------------------------------------------------- 1 | package executor 2 | 3 | import ( 4 | "io" 5 | 6 | "code.cloudfoundry.org/lager/v3" 7 | "code.cloudfoundry.org/routing-info/internalroutes" 8 | ) 9 | 10 | //go:generate counterfeiter -o fakes/fake_client.go . Client 11 | 12 | type Client interface { 13 | Ping(logger lager.Logger) error 14 | AllocateContainers(logger lager.Logger, traceID string, requests []AllocationRequest) []AllocationFailure 15 | GetContainer(logger lager.Logger, guid string) (Container, error) 16 | RunContainer(lager.Logger, string, *RunRequest) error 17 | UpdateContainer(lager.Logger, *UpdateRequest) error 18 | StopContainer(logger lager.Logger, traceID string, guid string) error 19 | DeleteContainer(logger lager.Logger, traceID string, guid string) error 20 | ListContainers(lager.Logger) ([]Container, error) 21 | GetBulkMetrics(lager.Logger) (map[string]Metrics, error) 22 | RemainingResources(lager.Logger) (ExecutorResources, error) 23 | TotalResources(lager.Logger) (ExecutorResources, error) 24 | GetFiles(logger lager.Logger, guid string, path string) (io.ReadCloser, error) 25 | VolumeDrivers(logger lager.Logger) ([]string, error) 26 | SubscribeToEvents(lager.Logger) (EventSource, error) 27 | Healthy(lager.Logger) bool 28 | SetHealthy(lager.Logger, bool) 29 | Cleanup(lager.Logger) 30 | } 31 | 32 | //go:generate counterfeiter -o fakes/fake_event_source.go . EventSource 33 | 34 | type EventSource interface { 35 | Next() (Event, error) 36 | Close() error 37 | } 38 | 39 | type AllocationRequest struct { 40 | Guid string 41 | GenerateLogMetrics bool 42 | Resource 43 | Tags 44 | } 45 | 46 | func NewAllocationRequest(guid string, resource *Resource, generateLogMetrics bool, tags Tags) AllocationRequest { 47 | return AllocationRequest{ 48 | Guid: guid, 49 | GenerateLogMetrics: generateLogMetrics, 50 | Resource: *resource, 51 | Tags: tags, 52 | } 53 | } 54 | 55 | func (a *AllocationRequest) Validate() error { 56 | if a.Guid == "" { 57 | return ErrGuidNotSpecified 58 | } 59 | return nil 60 | } 61 | 62 | type AllocationFailure struct { 63 | AllocationRequest 64 | ErrorMsg string 65 | } 66 | 67 | func (fail *AllocationFailure) Error() string { 68 | return fail.ErrorMsg 69 | } 70 | 71 | func NewAllocationFailure(req *AllocationRequest, msg string) AllocationFailure { 72 | return AllocationFailure{ 73 | AllocationRequest: *req, 74 | ErrorMsg: msg, 75 | } 76 | } 77 | 78 | type RunRequest struct { 79 | Guid string 80 | RunInfo 81 | Tags 82 | } 83 | 84 | func NewRunRequest(guid string, runInfo *RunInfo, tags Tags) RunRequest { 85 | return RunRequest{ 86 | Guid: guid, 87 | RunInfo: *runInfo, 88 | Tags: tags, 89 | } 90 | } 91 | 92 | type UpdateRequest struct { 93 | Guid string 94 | InternalRoutes internalroutes.InternalRoutes 95 | MetricTags map[string]string 96 | } 97 | 98 | func NewUpdateRequest(guid string, internalRoutes internalroutes.InternalRoutes, metricTags map[string]string) UpdateRequest { 99 | return UpdateRequest{ 100 | Guid: guid, 101 | InternalRoutes: internalRoutes, 102 | MetricTags: metricTags, 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /client_test.go: -------------------------------------------------------------------------------- 1 | package executor_test 2 | 3 | import ( 4 | . "code.cloudfoundry.org/executor" 5 | . "github.com/onsi/ginkgo/v2" 6 | . "github.com/onsi/gomega" 7 | ) 8 | 9 | var _ = Describe("Allocation Request", func() { 10 | It("is invalid when the guid is empty", func() { 11 | allocationInfo := NewResource(20, 30, 1024) 12 | allocRequest := NewAllocationRequest("", &allocationInfo, false, nil) 13 | err := allocRequest.Validate() 14 | Expect(err).To(HaveOccurred()) 15 | Expect(err).To(MatchError(ErrGuidNotSpecified)) 16 | }) 17 | }) 18 | -------------------------------------------------------------------------------- /containermetrics/cached_container_metric.go: -------------------------------------------------------------------------------- 1 | package containermetrics 2 | 3 | type CachedContainerMetrics struct { 4 | MetricGUID string `json:"metric_guid"` 5 | CPUUsageFraction float64 `json:"cpu_usage_fraction"` 6 | DiskUsageBytes uint64 `json:"disk_usage_bytes"` 7 | DiskQuotaBytes uint64 `json:"disk_quota_bytes"` 8 | MemoryUsageBytes uint64 `json:"memory_usage_bytes"` 9 | MemoryQuotaBytes uint64 `json:"memory_quota_bytes"` 10 | RxBytes *uint64 `json:"rx_bytes,omitempty"` 11 | TxBytes *uint64 `json:"tx_bytes,omitempty"` 12 | } 13 | -------------------------------------------------------------------------------- /containermetrics/cpu_spike_reporter.go: -------------------------------------------------------------------------------- 1 | package containermetrics 2 | 3 | import ( 4 | "time" 5 | 6 | loggingclient "code.cloudfoundry.org/diego-logging-client" 7 | "code.cloudfoundry.org/executor" 8 | "code.cloudfoundry.org/lager/v3" 9 | ) 10 | 11 | type spikeInfo struct { 12 | start time.Time 13 | end time.Time 14 | } 15 | 16 | type CPUSpikeReporter struct { 17 | spikeInfos map[string]*spikeInfo 18 | metronClient loggingclient.IngressClient 19 | } 20 | 21 | func NewCPUSpikeReporter(metronClient loggingclient.IngressClient) *CPUSpikeReporter { 22 | return &CPUSpikeReporter{ 23 | spikeInfos: make(map[string]*spikeInfo), 24 | metronClient: metronClient, 25 | } 26 | } 27 | 28 | func (reporter *CPUSpikeReporter) Report(logger lager.Logger, containers []executor.Container, metrics map[string]executor.Metrics, timeStamp time.Time) error { 29 | spikeInfos := map[string]*spikeInfo{} 30 | 31 | for _, container := range containers { 32 | guid := container.Guid 33 | metric, ok := metrics[guid] 34 | if !ok { 35 | continue 36 | } 37 | 38 | spikeInfos[guid] = reporter.spikeInfos[guid] 39 | 40 | previousSpikeInfo := spikeInfos[guid] 41 | currentSpikeInfo := &spikeInfo{} 42 | 43 | if previousSpikeInfo != nil { 44 | currentSpikeInfo.start = previousSpikeInfo.start 45 | currentSpikeInfo.end = previousSpikeInfo.end 46 | } 47 | 48 | if spikeStarted(metric, previousSpikeInfo) { 49 | currentSpikeInfo.start = timeStamp 50 | currentSpikeInfo.end = time.Time{} 51 | } 52 | 53 | if spikeEnded(metric, previousSpikeInfo) { 54 | currentSpikeInfo.end = timeStamp 55 | } 56 | 57 | spikeInfos[guid] = currentSpikeInfo 58 | 59 | if !currentSpikeInfo.start.IsZero() { 60 | err := reporter.metronClient.SendSpikeMetrics(loggingclient.SpikeMetric{ 61 | Start: currentSpikeInfo.start, 62 | End: currentSpikeInfo.end, 63 | Tags: metric.MetricsConfig.Tags, 64 | }) 65 | if err != nil { 66 | return err 67 | } 68 | } 69 | } 70 | 71 | reporter.spikeInfos = spikeInfos 72 | return nil 73 | } 74 | 75 | func spikeStarted(metric executor.Metrics, previousSpikeInfo *spikeInfo) bool { 76 | currentlySpiking := uint64(metric.TimeSpentInCPU.Nanoseconds()) > metric.AbsoluteCPUEntitlementInNanoseconds 77 | previouslySpiking := previousSpikeInfo != nil && !previousSpikeInfo.start.IsZero() && previousSpikeInfo.end.IsZero() 78 | return currentlySpiking && !previouslySpiking 79 | } 80 | 81 | func spikeEnded(metric executor.Metrics, previousSpikeInfo *spikeInfo) bool { 82 | currentlySpiking := uint64(metric.TimeSpentInCPU.Nanoseconds()) > metric.AbsoluteCPUEntitlementInNanoseconds 83 | previouslySpiking := previousSpikeInfo != nil && !previousSpikeInfo.start.IsZero() && previousSpikeInfo.end.IsZero() 84 | return !currentlySpiking && previouslySpiking 85 | } 86 | -------------------------------------------------------------------------------- /containermetrics/metrics_suite_test.go: -------------------------------------------------------------------------------- 1 | package containermetrics_test 2 | 3 | import ( 4 | . "github.com/onsi/ginkgo/v2" 5 | . "github.com/onsi/gomega" 6 | 7 | "testing" 8 | ) 9 | 10 | func TestContainerMetrics(t *testing.T) { 11 | RegisterFailHandler(Fail) 12 | RunSpecs(t, "ContainerMetrics Suite") 13 | } 14 | -------------------------------------------------------------------------------- /containermetrics/package.go: -------------------------------------------------------------------------------- 1 | package containermetrics // import "code.cloudfoundry.org/executor/containermetrics" 2 | -------------------------------------------------------------------------------- /containermetrics/reporters_runner.go: -------------------------------------------------------------------------------- 1 | package containermetrics 2 | 3 | import ( 4 | "os" 5 | "time" 6 | 7 | "code.cloudfoundry.org/clock" 8 | "code.cloudfoundry.org/executor" 9 | "code.cloudfoundry.org/lager/v3" 10 | ) 11 | 12 | type ReportersRunner struct { 13 | logger lager.Logger 14 | 15 | interval time.Duration 16 | clock clock.Clock 17 | executorClient executor.Client 18 | metricsReporters []MetricsReporter 19 | } 20 | 21 | type MetricsReporter interface { 22 | Report(logger lager.Logger, containers []executor.Container, metrics map[string]executor.Metrics, timeStamp time.Time) error 23 | } 24 | 25 | func NewReportersRunner(logger lager.Logger, 26 | interval time.Duration, 27 | clock clock.Clock, 28 | executorClient executor.Client, 29 | metricsReporters ...MetricsReporter, 30 | ) *ReportersRunner { 31 | return &ReportersRunner{ 32 | logger: logger, 33 | 34 | interval: interval, 35 | clock: clock, 36 | executorClient: executorClient, 37 | metricsReporters: metricsReporters, 38 | } 39 | } 40 | 41 | func (reporterRunner *ReportersRunner) Run(signals <-chan os.Signal, ready chan<- struct{}) error { 42 | logger := reporterRunner.logger.Session("container-metrics-reporterRunner") 43 | 44 | ticker := reporterRunner.clock.NewTicker(reporterRunner.interval) 45 | defer ticker.Stop() 46 | 47 | close(ready) 48 | 49 | for { 50 | select { 51 | case signal := <-signals: 52 | logger.Info("signalled", lager.Data{"signal": signal.String()}) 53 | return nil 54 | 55 | case now := <-ticker.C(): 56 | reporterRunner.fetchMetrics(logger, now, reporterRunner.metricsReporters...) 57 | } 58 | } 59 | } 60 | 61 | func (reporterRunner *ReportersRunner) fetchMetrics(logger lager.Logger, timeStamp time.Time, reporters ...MetricsReporter) { 62 | logger = logger.Session("tick") 63 | 64 | startTime := reporterRunner.clock.Now() 65 | 66 | logger.Debug("started") 67 | defer func() { 68 | logger.Debug("done", lager.Data{ 69 | "took": reporterRunner.clock.Now().Sub(startTime).String(), 70 | }) 71 | }() 72 | 73 | metricsCache, err := reporterRunner.executorClient.GetBulkMetrics(logger) 74 | if err != nil { 75 | logger.Error("failed-to-get-all-metrics", err) 76 | return 77 | } 78 | 79 | logger.Debug("emitting", lager.Data{ 80 | "total-containers": len(metricsCache), 81 | "get-metrics-took": reporterRunner.clock.Now().Sub(startTime).String(), 82 | }) 83 | 84 | containers, err := reporterRunner.executorClient.ListContainers(logger) 85 | if err != nil { 86 | logger.Error("failed-to-fetch-containers", err) 87 | return 88 | } 89 | 90 | for _, reporter := range reporters { 91 | err := reporter.Report(logger, containers, metricsCache, timeStamp) 92 | if err != nil { 93 | logger.Error("failed-to-report-metric", err, lager.Data{"containers": containers, "metrics": metricsCache, "reporter": reporter}) 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /depot/containerstore/containerreaper.go: -------------------------------------------------------------------------------- 1 | package containerstore 2 | 3 | import ( 4 | "os" 5 | 6 | "code.cloudfoundry.org/clock" 7 | "code.cloudfoundry.org/executor" 8 | "code.cloudfoundry.org/garden" 9 | "code.cloudfoundry.org/lager/v3" 10 | ) 11 | 12 | type containerReaper struct { 13 | logger lager.Logger 14 | config *ContainerConfig 15 | clock clock.Clock 16 | containers *nodeMap 17 | gardenClient garden.Client 18 | } 19 | 20 | func newContainerReaper(logger lager.Logger, config *ContainerConfig, clock clock.Clock, containers *nodeMap, gardenClient garden.Client) *containerReaper { 21 | return &containerReaper{ 22 | logger: logger, 23 | config: config, 24 | clock: clock, 25 | containers: containers, 26 | gardenClient: gardenClient, 27 | } 28 | } 29 | 30 | func (r *containerReaper) Run(signals <-chan os.Signal, ready chan<- struct{}) error { 31 | logger := r.logger.Session("container-reaper") 32 | timer := r.clock.NewTimer(r.config.ReapInterval) 33 | traceID := "" // requests to reap are not originated through API 34 | 35 | close(ready) 36 | 37 | for { 38 | select { 39 | case <-timer.C(): 40 | err := r.reapExtraGardenContainers(logger.Session("reap-extra-garden-containers")) 41 | if err != nil { 42 | logger.Error("failed-to-reap-extra-containers", err) 43 | } 44 | 45 | err = r.reapMissingGardenContainers(logger.Session("reap-missing-garden-containers"), traceID) 46 | if err != nil { 47 | logger.Error("failed-to-reap-missing-containers", err) 48 | } 49 | 50 | case signal := <-signals: 51 | logger.Info("signalled", lager.Data{"signal": signal.String()}) 52 | return nil 53 | } 54 | 55 | timer.Reset(r.config.ReapInterval) 56 | } 57 | } 58 | 59 | func (r *containerReaper) reapExtraGardenContainers(logger lager.Logger) error { 60 | logger.Info("starting") 61 | defer logger.Info("complete") 62 | 63 | handles, err := r.fetchGardenContainerHandles(logger) 64 | if err != nil { 65 | return err 66 | } 67 | 68 | for key := range handles { 69 | if !r.containers.Contains(key) { 70 | err := r.gardenClient.Destroy(key) 71 | if err != nil { 72 | logger.Error("failed-to-destroy-container", err, lager.Data{"handle": key}) 73 | } 74 | } 75 | } 76 | 77 | return nil 78 | } 79 | 80 | func (r *containerReaper) reapMissingGardenContainers(logger lager.Logger, traceID string) error { 81 | logger.Info("starting") 82 | defer logger.Info("complete") 83 | 84 | snapshotGuids := r.containers.containerGuids(logger) 85 | handles, err := r.fetchGardenContainerHandles(logger) 86 | if err != nil { 87 | return err 88 | } 89 | 90 | r.containers.CompleteMissing(logger, traceID, snapshotGuids, handles) 91 | 92 | return nil 93 | } 94 | 95 | func (r *containerReaper) fetchGardenContainerHandles(logger lager.Logger) (map[string]struct{}, error) { 96 | properties := garden.Properties{ 97 | executor.ContainerOwnerProperty: r.config.OwnerName, 98 | } 99 | 100 | gardenContainers, err := r.gardenClient.Containers(properties) 101 | if err != nil { 102 | logger.Error("failed-to-fetch-containers", err) 103 | return nil, err 104 | } 105 | 106 | handles := make(map[string]struct{}) 107 | for _, gardenContainer := range gardenContainers { 108 | handles[gardenContainer.Handle()] = struct{}{} 109 | } 110 | return handles, nil 111 | } 112 | -------------------------------------------------------------------------------- /depot/containerstore/containerstore_suite_test.go: -------------------------------------------------------------------------------- 1 | package containerstore_test 2 | 3 | import ( 4 | "time" 5 | 6 | "code.cloudfoundry.org/lager/v3/lagertest" 7 | . "github.com/onsi/ginkgo/v2" 8 | . "github.com/onsi/gomega" 9 | 10 | "testing" 11 | ) 12 | 13 | var logger *lagertest.TestLogger 14 | 15 | func TestContainerstore(t *testing.T) { 16 | SetDefaultConsistentlyDuration(5 * time.Second) 17 | SetDefaultEventuallyTimeout(5 * time.Second) 18 | RegisterFailHandler(Fail) 19 | 20 | RunSpecs(t, "Containerstore Suite") 21 | } 22 | 23 | var _ = BeforeEach(func() { 24 | logger = lagertest.NewTestLogger("test") 25 | }) 26 | -------------------------------------------------------------------------------- /depot/containerstore/containerstorefakes/fake_container_info_provider.go: -------------------------------------------------------------------------------- 1 | // Code generated by counterfeiter. DO NOT EDIT. 2 | package containerstorefakes 3 | 4 | import ( 5 | "sync" 6 | 7 | "code.cloudfoundry.org/executor" 8 | "code.cloudfoundry.org/executor/depot/containerstore" 9 | ) 10 | 11 | type FakeContainerInfoProvider struct { 12 | InfoStub func() executor.Container 13 | infoMutex sync.RWMutex 14 | infoArgsForCall []struct { 15 | } 16 | infoReturns struct { 17 | result1 executor.Container 18 | } 19 | infoReturnsOnCall map[int]struct { 20 | result1 executor.Container 21 | } 22 | invocations map[string][][]interface{} 23 | invocationsMutex sync.RWMutex 24 | } 25 | 26 | func (fake *FakeContainerInfoProvider) Info() executor.Container { 27 | fake.infoMutex.Lock() 28 | ret, specificReturn := fake.infoReturnsOnCall[len(fake.infoArgsForCall)] 29 | fake.infoArgsForCall = append(fake.infoArgsForCall, struct { 30 | }{}) 31 | stub := fake.InfoStub 32 | fakeReturns := fake.infoReturns 33 | fake.recordInvocation("Info", []interface{}{}) 34 | fake.infoMutex.Unlock() 35 | if stub != nil { 36 | return stub() 37 | } 38 | if specificReturn { 39 | return ret.result1 40 | } 41 | return fakeReturns.result1 42 | } 43 | 44 | func (fake *FakeContainerInfoProvider) InfoCallCount() int { 45 | fake.infoMutex.RLock() 46 | defer fake.infoMutex.RUnlock() 47 | return len(fake.infoArgsForCall) 48 | } 49 | 50 | func (fake *FakeContainerInfoProvider) InfoCalls(stub func() executor.Container) { 51 | fake.infoMutex.Lock() 52 | defer fake.infoMutex.Unlock() 53 | fake.InfoStub = stub 54 | } 55 | 56 | func (fake *FakeContainerInfoProvider) InfoReturns(result1 executor.Container) { 57 | fake.infoMutex.Lock() 58 | defer fake.infoMutex.Unlock() 59 | fake.InfoStub = nil 60 | fake.infoReturns = struct { 61 | result1 executor.Container 62 | }{result1} 63 | } 64 | 65 | func (fake *FakeContainerInfoProvider) InfoReturnsOnCall(i int, result1 executor.Container) { 66 | fake.infoMutex.Lock() 67 | defer fake.infoMutex.Unlock() 68 | fake.InfoStub = nil 69 | if fake.infoReturnsOnCall == nil { 70 | fake.infoReturnsOnCall = make(map[int]struct { 71 | result1 executor.Container 72 | }) 73 | } 74 | fake.infoReturnsOnCall[i] = struct { 75 | result1 executor.Container 76 | }{result1} 77 | } 78 | 79 | func (fake *FakeContainerInfoProvider) Invocations() map[string][][]interface{} { 80 | fake.invocationsMutex.RLock() 81 | defer fake.invocationsMutex.RUnlock() 82 | fake.infoMutex.RLock() 83 | defer fake.infoMutex.RUnlock() 84 | copiedInvocations := map[string][][]interface{}{} 85 | for key, value := range fake.invocations { 86 | copiedInvocations[key] = value 87 | } 88 | return copiedInvocations 89 | } 90 | 91 | func (fake *FakeContainerInfoProvider) recordInvocation(key string, args []interface{}) { 92 | fake.invocationsMutex.Lock() 93 | defer fake.invocationsMutex.Unlock() 94 | if fake.invocations == nil { 95 | fake.invocations = map[string][][]interface{}{} 96 | } 97 | if fake.invocations[key] == nil { 98 | fake.invocations[key] = [][]interface{}{} 99 | } 100 | fake.invocations[key] = append(fake.invocations[key], args) 101 | } 102 | 103 | var _ containerstore.ContainerInfoProvider = new(FakeContainerInfoProvider) 104 | -------------------------------------------------------------------------------- /depot/containerstore/containerstorefakes/fake_garden_client_factory.go: -------------------------------------------------------------------------------- 1 | // Code generated by counterfeiter. DO NOT EDIT. 2 | package containerstorefakes 3 | 4 | import ( 5 | "sync" 6 | 7 | "code.cloudfoundry.org/executor/depot/containerstore" 8 | "code.cloudfoundry.org/garden" 9 | lager "code.cloudfoundry.org/lager/v3" 10 | ) 11 | 12 | type FakeGardenClientFactory struct { 13 | NewGardenClientStub func(lager.Logger, string) garden.Client 14 | newGardenClientMutex sync.RWMutex 15 | newGardenClientArgsForCall []struct { 16 | arg1 lager.Logger 17 | arg2 string 18 | } 19 | newGardenClientReturns struct { 20 | result1 garden.Client 21 | } 22 | newGardenClientReturnsOnCall map[int]struct { 23 | result1 garden.Client 24 | } 25 | invocations map[string][][]interface{} 26 | invocationsMutex sync.RWMutex 27 | } 28 | 29 | func (fake *FakeGardenClientFactory) NewGardenClient(arg1 lager.Logger, arg2 string) garden.Client { 30 | fake.newGardenClientMutex.Lock() 31 | ret, specificReturn := fake.newGardenClientReturnsOnCall[len(fake.newGardenClientArgsForCall)] 32 | fake.newGardenClientArgsForCall = append(fake.newGardenClientArgsForCall, struct { 33 | arg1 lager.Logger 34 | arg2 string 35 | }{arg1, arg2}) 36 | stub := fake.NewGardenClientStub 37 | fakeReturns := fake.newGardenClientReturns 38 | fake.recordInvocation("NewGardenClient", []interface{}{arg1, arg2}) 39 | fake.newGardenClientMutex.Unlock() 40 | if stub != nil { 41 | return stub(arg1, arg2) 42 | } 43 | if specificReturn { 44 | return ret.result1 45 | } 46 | return fakeReturns.result1 47 | } 48 | 49 | func (fake *FakeGardenClientFactory) NewGardenClientCallCount() int { 50 | fake.newGardenClientMutex.RLock() 51 | defer fake.newGardenClientMutex.RUnlock() 52 | return len(fake.newGardenClientArgsForCall) 53 | } 54 | 55 | func (fake *FakeGardenClientFactory) NewGardenClientCalls(stub func(lager.Logger, string) garden.Client) { 56 | fake.newGardenClientMutex.Lock() 57 | defer fake.newGardenClientMutex.Unlock() 58 | fake.NewGardenClientStub = stub 59 | } 60 | 61 | func (fake *FakeGardenClientFactory) NewGardenClientArgsForCall(i int) (lager.Logger, string) { 62 | fake.newGardenClientMutex.RLock() 63 | defer fake.newGardenClientMutex.RUnlock() 64 | argsForCall := fake.newGardenClientArgsForCall[i] 65 | return argsForCall.arg1, argsForCall.arg2 66 | } 67 | 68 | func (fake *FakeGardenClientFactory) NewGardenClientReturns(result1 garden.Client) { 69 | fake.newGardenClientMutex.Lock() 70 | defer fake.newGardenClientMutex.Unlock() 71 | fake.NewGardenClientStub = nil 72 | fake.newGardenClientReturns = struct { 73 | result1 garden.Client 74 | }{result1} 75 | } 76 | 77 | func (fake *FakeGardenClientFactory) NewGardenClientReturnsOnCall(i int, result1 garden.Client) { 78 | fake.newGardenClientMutex.Lock() 79 | defer fake.newGardenClientMutex.Unlock() 80 | fake.NewGardenClientStub = nil 81 | if fake.newGardenClientReturnsOnCall == nil { 82 | fake.newGardenClientReturnsOnCall = make(map[int]struct { 83 | result1 garden.Client 84 | }) 85 | } 86 | fake.newGardenClientReturnsOnCall[i] = struct { 87 | result1 garden.Client 88 | }{result1} 89 | } 90 | 91 | func (fake *FakeGardenClientFactory) Invocations() map[string][][]interface{} { 92 | fake.invocationsMutex.RLock() 93 | defer fake.invocationsMutex.RUnlock() 94 | fake.newGardenClientMutex.RLock() 95 | defer fake.newGardenClientMutex.RUnlock() 96 | copiedInvocations := map[string][][]interface{}{} 97 | for key, value := range fake.invocations { 98 | copiedInvocations[key] = value 99 | } 100 | return copiedInvocations 101 | } 102 | 103 | func (fake *FakeGardenClientFactory) recordInvocation(key string, args []interface{}) { 104 | fake.invocationsMutex.Lock() 105 | defer fake.invocationsMutex.Unlock() 106 | if fake.invocations == nil { 107 | fake.invocations = map[string][][]interface{}{} 108 | } 109 | if fake.invocations[key] == nil { 110 | fake.invocations[key] = [][]interface{}{} 111 | } 112 | fake.invocations[key] = append(fake.invocations[key], args) 113 | } 114 | 115 | var _ containerstore.GardenClientFactory = new(FakeGardenClientFactory) 116 | -------------------------------------------------------------------------------- /depot/containerstore/containerstorefakes/package.go: -------------------------------------------------------------------------------- 1 | package containerstorefakes // import "code.cloudfoundry.org/executor/depot/containerstore/containerstorefakes" 2 | -------------------------------------------------------------------------------- /depot/containerstore/garden_client_factory.go: -------------------------------------------------------------------------------- 1 | package containerstore 2 | 3 | import ( 4 | "net/http" 5 | 6 | "code.cloudfoundry.org/garden" 7 | gardenclient "code.cloudfoundry.org/garden/client" 8 | "code.cloudfoundry.org/garden/client/connection" 9 | "code.cloudfoundry.org/lager/v3" 10 | ) 11 | 12 | //go:generate counterfeiter -o containerstorefakes/fake_garden_client_factory.go . GardenClientFactory 13 | type GardenClientFactory interface { 14 | NewGardenClient(logger lager.Logger, traceID string) garden.Client 15 | } 16 | 17 | type gardenClientFactory struct { 18 | network string 19 | address string 20 | } 21 | 22 | func NewGardenClientFactory(network, address string) GardenClientFactory { 23 | return &gardenClientFactory{ 24 | network: network, 25 | address: address, 26 | } 27 | } 28 | 29 | func (f *gardenClientFactory) NewGardenClient(logger lager.Logger, traceID string) garden.Client { 30 | hijacker := connection.NewHijackStreamerWithHeaders(f.network, f.address, http.Header{lager.RequestIdHeader: []string{traceID}}) 31 | return gardenclient.New(connection.NewWithHijacker(hijacker, logger)) 32 | } 33 | -------------------------------------------------------------------------------- /depot/containerstore/helpers.go: -------------------------------------------------------------------------------- 1 | package containerstore 2 | 3 | import ( 4 | "errors" 5 | "net" 6 | "strings" 7 | 8 | "code.cloudfoundry.org/bbs/models" 9 | "code.cloudfoundry.org/executor" 10 | "code.cloudfoundry.org/garden" 11 | "code.cloudfoundry.org/lager/v3" 12 | ) 13 | 14 | var ErrIPRangeConversionFailed = errors.New("failed to convert destination to ip range") 15 | 16 | func newBindMount(src, dst string) garden.BindMount { 17 | return garden.BindMount{ 18 | SrcPath: src, 19 | DstPath: dst, 20 | Mode: garden.BindMountModeRO, 21 | Origin: garden.BindMountOriginHost, 22 | } 23 | } 24 | 25 | func convertEnvVars(execEnv []executor.EnvironmentVariable) []string { 26 | env := make([]string, len(execEnv)) 27 | for i := range execEnv { 28 | envVar := &execEnv[i] 29 | env[i] = envVar.Name + "=" + envVar.Value 30 | } 31 | return env 32 | } 33 | 34 | func convertEgressToNetOut(logger lager.Logger, egressRules []*models.SecurityGroupRule) ([]garden.NetOutRule, error) { 35 | netOutRules := make([]garden.NetOutRule, 0, len(egressRules)) 36 | for _, rule := range egressRules { 37 | if err := rule.Validate(); err != nil { 38 | logger.Error("invalid-egress-rule", err) 39 | return nil, err 40 | } 41 | 42 | nextNetOutRuleSet, err := securityGroupRuleToNetOutRules(rule) 43 | if err != nil { 44 | logger.Error("failed-to-convert-to-net-out-rule", err) 45 | return nil, err 46 | } 47 | 48 | netOutRules = append(netOutRules, nextNetOutRuleSet...) 49 | } 50 | return netOutRules, nil 51 | } 52 | 53 | func securityGroupRuleToNetOutRules(securityRule *models.SecurityGroupRule) ([]garden.NetOutRule, error) { 54 | var protocol garden.Protocol 55 | var portRanges []garden.PortRange 56 | var icmp *garden.ICMPControl 57 | 58 | switch securityRule.Protocol { 59 | case models.TCPProtocol: 60 | protocol = garden.ProtocolTCP 61 | case models.UDPProtocol: 62 | protocol = garden.ProtocolUDP 63 | case models.ICMPProtocol: 64 | protocol = garden.ProtocolICMP 65 | icmp = &garden.ICMPControl{ 66 | Type: garden.ICMPType(securityRule.IcmpInfo.Type), 67 | Code: garden.ICMPControlCode(uint8(securityRule.IcmpInfo.Code)), 68 | } 69 | case models.AllProtocol: 70 | protocol = garden.ProtocolAll 71 | } 72 | 73 | if securityRule.PortRange != nil { 74 | portRanges = append(portRanges, garden.PortRange{Start: uint16(securityRule.PortRange.Start), End: uint16(securityRule.PortRange.End)}) 75 | } else if securityRule.Ports != nil { 76 | for _, port := range securityRule.Ports { 77 | portRanges = append(portRanges, garden.PortRangeFromPort(uint16(port))) 78 | } 79 | } 80 | 81 | var destinations []string 82 | for _, d := range securityRule.Destinations { 83 | destinations = append(destinations, strings.Split(d, ",")...) 84 | } 85 | 86 | var netOutRules []garden.NetOutRule 87 | 88 | for _, dest := range destinations { 89 | ipRange, err := toIPRange(dest) 90 | if err != nil { 91 | return nil, err 92 | } 93 | 94 | var networks []garden.IPRange 95 | networks = append(networks, ipRange) 96 | 97 | newRule := garden.NetOutRule{ 98 | Protocol: protocol, 99 | Networks: networks, 100 | Ports: portRanges, 101 | ICMPs: icmp, 102 | Log: securityRule.Log, 103 | } 104 | 105 | netOutRules = append(netOutRules, newRule) 106 | } 107 | 108 | return netOutRules, nil 109 | } 110 | 111 | func toIPRange(dest string) (garden.IPRange, error) { 112 | idx := strings.IndexAny(dest, "-/") 113 | 114 | // Not a range or a CIDR 115 | if idx == -1 { 116 | ip := net.ParseIP(dest) 117 | if ip == nil { 118 | return garden.IPRange{}, ErrIPRangeConversionFailed 119 | } 120 | 121 | return garden.IPRangeFromIP(ip), nil 122 | } 123 | 124 | // We have a CIDR 125 | if dest[idx] == '/' { 126 | _, ipNet, err := net.ParseCIDR(dest) 127 | if err != nil { 128 | return garden.IPRange{}, ErrIPRangeConversionFailed 129 | } 130 | 131 | return garden.IPRangeFromIPNet(ipNet), nil 132 | } 133 | 134 | // We have an IP range 135 | firstIP := net.ParseIP(dest[:idx]) 136 | secondIP := net.ParseIP(dest[idx+1:]) 137 | if firstIP == nil || secondIP == nil { 138 | return garden.IPRange{}, ErrIPRangeConversionFailed 139 | } 140 | 141 | return garden.IPRange{Start: firstIP, End: secondIP}, nil 142 | } 143 | -------------------------------------------------------------------------------- /depot/containerstore/instance_identity_handler.go: -------------------------------------------------------------------------------- 1 | package containerstore 2 | 3 | import ( 4 | "os" 5 | "path" 6 | "path/filepath" 7 | 8 | "code.cloudfoundry.org/executor" 9 | "code.cloudfoundry.org/garden" 10 | "code.cloudfoundry.org/lager/v3" 11 | ) 12 | 13 | func NewInstanceIdentityHandler( 14 | credDir string, 15 | containerMountPath string, 16 | ) *InstanceIdentityHandler { 17 | return &InstanceIdentityHandler{ 18 | credDir: credDir, 19 | containerMountPath: containerMountPath, 20 | } 21 | } 22 | 23 | type InstanceIdentityHandler struct { 24 | containerMountPath string 25 | credDir string 26 | } 27 | 28 | func (h *InstanceIdentityHandler) CreateDir(logger lager.Logger, container executor.Container) ([]garden.BindMount, []executor.EnvironmentVariable, error) { 29 | containerDir := filepath.Join(h.credDir, container.Guid) 30 | err := os.Mkdir(containerDir, 0755) 31 | if err != nil { 32 | return nil, nil, err 33 | } 34 | 35 | return []garden.BindMount{ 36 | { 37 | SrcPath: containerDir, 38 | DstPath: h.containerMountPath, 39 | Mode: garden.BindMountModeRO, 40 | Origin: garden.BindMountOriginHost, 41 | }, 42 | }, []executor.EnvironmentVariable{ 43 | {Name: "CF_INSTANCE_CERT", Value: path.Join(h.containerMountPath, "instance.crt")}, 44 | {Name: "CF_INSTANCE_KEY", Value: path.Join(h.containerMountPath, "instance.key")}, 45 | }, nil 46 | } 47 | 48 | func (h *InstanceIdentityHandler) RemoveDir(logger lager.Logger, container executor.Container) error { 49 | return os.RemoveAll(filepath.Join(h.credDir, container.Guid)) 50 | } 51 | 52 | func (h *InstanceIdentityHandler) Update(creds Credentials, container executor.Container) error { 53 | if creds.InstanceIdentityCredential.IsEmpty() { 54 | return nil 55 | } 56 | 57 | instanceKeyPath := filepath.Join(h.credDir, container.Guid, "instance.key") 58 | tmpInstanceKeyPath := instanceKeyPath + ".tmp" 59 | certificatePath := filepath.Join(h.credDir, container.Guid, "instance.crt") 60 | tmpCertificatePath := certificatePath + ".tmp" 61 | 62 | instanceKey, err := os.Create(tmpInstanceKeyPath) 63 | if err != nil { 64 | return err 65 | } 66 | defer instanceKey.Close() 67 | 68 | certificate, err := os.Create(tmpCertificatePath) 69 | if err != nil { 70 | return err 71 | } 72 | defer certificate.Close() 73 | 74 | _, err = certificate.Write([]byte(creds.InstanceIdentityCredential.Cert)) 75 | if err != nil { 76 | return err 77 | } 78 | 79 | _, err = instanceKey.Write([]byte(creds.InstanceIdentityCredential.Key)) 80 | if err != nil { 81 | return err 82 | } 83 | 84 | err = instanceKey.Close() 85 | if err != nil { 86 | return err 87 | } 88 | 89 | err = certificate.Close() 90 | if err != nil { 91 | return err 92 | } 93 | 94 | err = os.Rename(tmpInstanceKeyPath, instanceKeyPath) 95 | if err != nil { 96 | return err 97 | } 98 | 99 | err = os.Rename(tmpCertificatePath, certificatePath) 100 | if err != nil { 101 | return err 102 | } 103 | 104 | return nil 105 | } 106 | 107 | func (h *InstanceIdentityHandler) Close(creds Credentials, container executor.Container) error { 108 | return nil 109 | } 110 | -------------------------------------------------------------------------------- /depot/containerstore/log_manager.go: -------------------------------------------------------------------------------- 1 | package containerstore 2 | 3 | import ( 4 | "time" 5 | 6 | loggingclient "code.cloudfoundry.org/diego-logging-client" 7 | "code.cloudfoundry.org/executor" 8 | "code.cloudfoundry.org/executor/depot/log_streamer" 9 | ) 10 | 11 | //go:generate counterfeiter -o containerstorefakes/fake_log_manager.go . LogManager 12 | type LogManager interface { 13 | NewLogStreamer(conf executor.LogConfig, metronClient loggingclient.IngressClient, maxLogLinesPerSecond int, maxLogBytesPerSecond int64, metricReportInterval time.Duration) log_streamer.LogStreamer 14 | } 15 | 16 | type logManager struct{} 17 | 18 | func NewLogManager() LogManager { 19 | return &logManager{} 20 | } 21 | 22 | func (l *logManager) NewLogStreamer(conf executor.LogConfig, metronClient loggingclient.IngressClient, maxLogLinesPerSecond int, maxLogBytesPerSecond int64, metricReportInterval time.Duration) log_streamer.LogStreamer { 23 | return log_streamer.New( 24 | conf, 25 | metronClient, 26 | maxLogLinesPerSecond, 27 | maxLogBytesPerSecond, 28 | metricReportInterval, 29 | ) 30 | } 31 | -------------------------------------------------------------------------------- /depot/containerstore/nodemap.go: -------------------------------------------------------------------------------- 1 | package containerstore 2 | 3 | import ( 4 | "sync" 5 | "time" 6 | 7 | "code.cloudfoundry.org/executor" 8 | "code.cloudfoundry.org/lager/v3" 9 | ) 10 | 11 | type nodeMap struct { 12 | nodes map[string]*storeNode 13 | lock *sync.RWMutex 14 | 15 | remainingResources *executor.ExecutorResources 16 | } 17 | 18 | func newNodeMap(totalCapacity *executor.ExecutorResources) *nodeMap { 19 | capacity := totalCapacity.Copy() 20 | return &nodeMap{ 21 | nodes: make(map[string]*storeNode), 22 | lock: &sync.RWMutex{}, 23 | remainingResources: &capacity, 24 | } 25 | } 26 | 27 | func (n *nodeMap) Contains(guid string) bool { 28 | n.lock.RLock() 29 | defer n.lock.RUnlock() 30 | _, ok := n.nodes[guid] 31 | return ok 32 | } 33 | 34 | func (n *nodeMap) RemainingResources() executor.ExecutorResources { 35 | n.lock.RLock() 36 | defer n.lock.RUnlock() 37 | return n.remainingResources.Copy() 38 | } 39 | 40 | func (n *nodeMap) Add(node *storeNode) error { 41 | n.lock.Lock() 42 | defer n.lock.Unlock() 43 | 44 | info := node.Info() 45 | if _, ok := n.nodes[info.Guid]; ok { 46 | return executor.ErrContainerGuidNotAvailable 47 | } 48 | 49 | ok := n.remainingResources.Subtract(&info.Resource) 50 | if !ok { 51 | return executor.ErrInsufficientResourcesAvailable 52 | } 53 | 54 | n.nodes[info.Guid] = node 55 | 56 | return nil 57 | } 58 | 59 | func (n *nodeMap) Remove(guid string) { 60 | n.lock.Lock() 61 | defer n.lock.Unlock() 62 | 63 | node, ok := n.nodes[guid] 64 | if !ok { 65 | return 66 | } 67 | 68 | n.remove(node) 69 | } 70 | 71 | func (n *nodeMap) remove(node *storeNode) { 72 | info := node.Info() 73 | n.remainingResources.Add(&info.Resource) 74 | delete(n.nodes, info.Guid) 75 | } 76 | 77 | func (n *nodeMap) Get(guid string) (*storeNode, error) { 78 | n.lock.RLock() 79 | defer n.lock.RUnlock() 80 | 81 | node, ok := n.nodes[guid] 82 | if !ok { 83 | return nil, executor.ErrContainerNotFound 84 | } 85 | 86 | return node, nil 87 | } 88 | 89 | func (n *nodeMap) List() []*storeNode { 90 | n.lock.RLock() 91 | defer n.lock.RUnlock() 92 | 93 | list := make([]*storeNode, 0, len(n.nodes)) 94 | for _, node := range n.nodes { 95 | list = append(list, node) 96 | } 97 | return list 98 | } 99 | 100 | func (n *nodeMap) CompleteExpired(logger lager.Logger, traceID string, now time.Time) { 101 | n.lock.Lock() 102 | logger.Debug("lock-acquired") 103 | defer n.lock.Unlock() 104 | defer logger.Debug("lock-released") 105 | 106 | for i := range n.nodes { 107 | node := n.nodes[i] 108 | expired := node.Expire(logger, traceID, now) 109 | if expired { 110 | logger.Info("container-expired", lager.Data{"guid": node.Info().Guid}) 111 | } 112 | } 113 | } 114 | 115 | func (n *nodeMap) CompleteMissing(logger lager.Logger, traceID string, snapshotGuids map[string]struct{}, existingHandles map[string]struct{}) { 116 | n.lock.Lock() 117 | logger.Debug("lock-acquired") 118 | defer n.lock.Unlock() 119 | defer logger.Debug("lock-released") 120 | 121 | for guid := range snapshotGuids { 122 | if _, exist := existingHandles[guid]; !exist { 123 | node, ok := n.nodes[guid] 124 | if ok { 125 | reaped := node.Reap(logger, traceID) 126 | if reaped { 127 | logger.Info("reaped-missing-container", lager.Data{"guid": guid}) 128 | } 129 | } 130 | } 131 | } 132 | } 133 | 134 | func (n *nodeMap) containerGuids(logger lager.Logger) map[string]struct{} { 135 | n.lock.Lock() 136 | logger.Debug("lock-acquired") 137 | defer n.lock.Unlock() 138 | defer logger.Debug("lock-released") 139 | 140 | guids := make(map[string]struct{}) 141 | for guid := range n.nodes { 142 | guids[guid] = struct{}{} 143 | } 144 | return guids 145 | } 146 | -------------------------------------------------------------------------------- /depot/containerstore/package.go: -------------------------------------------------------------------------------- 1 | package containerstore // import "code.cloudfoundry.org/executor/depot/containerstore" 2 | -------------------------------------------------------------------------------- /depot/containerstore/registrypruner.go: -------------------------------------------------------------------------------- 1 | package containerstore 2 | 3 | import ( 4 | "os" 5 | 6 | "code.cloudfoundry.org/clock" 7 | "code.cloudfoundry.org/lager/v3" 8 | ) 9 | 10 | type registryPruner struct { 11 | logger lager.Logger 12 | config *ContainerConfig 13 | clock clock.Clock 14 | containers *nodeMap 15 | } 16 | 17 | func newRegistryPruner(logger lager.Logger, config *ContainerConfig, clock clock.Clock, containers *nodeMap) *registryPruner { 18 | return ®istryPruner{ 19 | logger: logger, 20 | config: config, 21 | clock: clock, 22 | containers: containers, 23 | } 24 | } 25 | 26 | func (r *registryPruner) Run(signals <-chan os.Signal, ready chan<- struct{}) error { 27 | logger := r.logger.Session("registry-pruner") 28 | ticker := r.clock.NewTicker(r.config.ReservedExpirationTime / 2) 29 | traceID := "" // completing expired containers is not oririnated through API 30 | 31 | close(ready) 32 | 33 | defer ticker.Stop() 34 | for { 35 | select { 36 | case <-ticker.C(): 37 | 38 | now := r.clock.Now() 39 | r.containers.CompleteExpired(logger, traceID, now) 40 | case signal := <-signals: 41 | logger.Info("signalled", lager.Data{"signal": signal.String()}) 42 | return nil 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /depot/depot_suite_test.go: -------------------------------------------------------------------------------- 1 | package depot_test 2 | 3 | import ( 4 | . "github.com/onsi/ginkgo/v2" 5 | . "github.com/onsi/gomega" 6 | 7 | "testing" 8 | ) 9 | 10 | func TestAllocationstore(t *testing.T) { 11 | RegisterFailHandler(Fail) 12 | RunSpecs(t, "Depot Suite") 13 | } 14 | -------------------------------------------------------------------------------- /depot/event/fakes/package.go: -------------------------------------------------------------------------------- 1 | package fakes // import "code.cloudfoundry.org/executor/depot/event/fakes" 2 | -------------------------------------------------------------------------------- /depot/event/hub.go: -------------------------------------------------------------------------------- 1 | package event 2 | 3 | import ( 4 | "code.cloudfoundry.org/eventhub" 5 | "code.cloudfoundry.org/executor" 6 | ) 7 | 8 | const SUBSCRIBER_BUFFER = 1024 9 | 10 | //go:generate counterfeiter -o fakes/fake_hub.go . Hub 11 | type Hub interface { 12 | Emit(executor.Event) 13 | Subscribe() (executor.EventSource, error) 14 | Close() error 15 | } 16 | 17 | func NewHub() Hub { 18 | return &hub{ 19 | rawHub: eventhub.NewNonBlocking(SUBSCRIBER_BUFFER), 20 | } 21 | } 22 | 23 | type hub struct { 24 | rawHub eventhub.Hub 25 | } 26 | 27 | func (hub *hub) Subscribe() (executor.EventSource, error) { 28 | rawSource, err := hub.rawHub.Subscribe() 29 | if err != nil { 30 | return nil, err 31 | } 32 | 33 | return executorSource{rawSource}, nil 34 | } 35 | 36 | func (hub *hub) Emit(ev executor.Event) { 37 | hub.rawHub.Emit(ev) 38 | } 39 | 40 | func (hub *hub) Close() error { 41 | return hub.rawHub.Close() 42 | } 43 | 44 | type executorSource struct { 45 | rawSource eventhub.Source 46 | } 47 | 48 | func (source executorSource) Next() (executor.Event, error) { 49 | ev, err := source.rawSource.Next() 50 | if err != nil { 51 | return nil, err 52 | } 53 | 54 | return ev.(executor.Event), nil 55 | } 56 | 57 | func (source executorSource) Close() error { 58 | return source.rawSource.Close() 59 | } 60 | -------------------------------------------------------------------------------- /depot/event/package.go: -------------------------------------------------------------------------------- 1 | package event // import "code.cloudfoundry.org/executor/depot/event" 2 | -------------------------------------------------------------------------------- /depot/log_streamer/buffer_streamer.go: -------------------------------------------------------------------------------- 1 | package log_streamer 2 | 3 | import "io" 4 | 5 | type bufferStreamer struct { 6 | stdout io.Writer 7 | stderr io.Writer 8 | sourceName string 9 | } 10 | 11 | func NewBufferStreamer(stdout, stderr io.Writer) LogStreamer { 12 | return &bufferStreamer{ 13 | stdout: stdout, 14 | stderr: stderr, 15 | sourceName: DefaultLogSource, 16 | } 17 | } 18 | 19 | func (bs *bufferStreamer) Stdout() io.Writer { 20 | return bs.stdout 21 | } 22 | 23 | func (bs *bufferStreamer) Stderr() io.Writer { 24 | return bs.stderr 25 | } 26 | 27 | func (bs *bufferStreamer) UpdateTags(tags map[string]string) { 28 | 29 | } 30 | 31 | func (bs *bufferStreamer) Flush() { 32 | } 33 | 34 | func (bs *bufferStreamer) WithSource(sourceName string) LogStreamer { 35 | bs.sourceName = sourceName 36 | return bs 37 | } 38 | 39 | func (bs *bufferStreamer) SourceName() string { 40 | return bs.sourceName 41 | } 42 | 43 | func (bs *bufferStreamer) Stop() {} 44 | -------------------------------------------------------------------------------- /depot/log_streamer/buffer_streamer_test.go: -------------------------------------------------------------------------------- 1 | package log_streamer_test 2 | 3 | import ( 4 | "bytes" 5 | 6 | "code.cloudfoundry.org/executor/depot/log_streamer" 7 | 8 | . "github.com/onsi/ginkgo/v2" 9 | . "github.com/onsi/gomega" 10 | ) 11 | 12 | var _ = Describe("BufferStreamer", func() { 13 | var ( 14 | outBuffer *bytes.Buffer 15 | errBuffer *bytes.Buffer 16 | streamer log_streamer.LogStreamer 17 | ) 18 | 19 | BeforeEach(func() { 20 | outBuffer = new(bytes.Buffer) 21 | errBuffer = new(bytes.Buffer) 22 | streamer = log_streamer.NewBufferStreamer(outBuffer, errBuffer) 23 | }) 24 | 25 | It("writes stdout to the buffer", func() { 26 | streamer.Stdout().Write([]byte("stdout")) 27 | 28 | output := make([]byte, 6) 29 | _, err := outBuffer.Read(output) 30 | Expect(err).NotTo(HaveOccurred()) 31 | Expect(output).To(Equal([]byte("stdout"))) 32 | }) 33 | 34 | It("writes stderr to the buffer", func() { 35 | streamer.Stderr().Write([]byte("stdout")) 36 | 37 | output := make([]byte, 6) 38 | _, err := errBuffer.Read(output) 39 | Expect(err).NotTo(HaveOccurred()) 40 | Expect(output).To(Equal([]byte("stdout"))) 41 | }) 42 | 43 | Describe("SourceName", func() { 44 | Context("when WithSource has not been called", func() { 45 | It("returns empty string", func() { 46 | Expect(streamer.SourceName()).To(Equal(log_streamer.DefaultLogSource)) 47 | }) 48 | }) 49 | 50 | Context("when WithSource has previously been called", func() { 51 | It("returns the source name passed to WithSource", func() { 52 | streamer = streamer.WithSource("test-log-source") 53 | Expect(streamer.SourceName()).To(Equal("test-log-source")) 54 | }) 55 | }) 56 | }) 57 | }) 58 | -------------------------------------------------------------------------------- /depot/log_streamer/concurrent_buffer.go: -------------------------------------------------------------------------------- 1 | package log_streamer 2 | 3 | import ( 4 | "bytes" 5 | "sync" 6 | ) 7 | 8 | type ConcurrentBuffer struct { 9 | Buffer *bytes.Buffer 10 | *sync.Mutex 11 | } 12 | 13 | func NewConcurrentBuffer(payload *bytes.Buffer) *ConcurrentBuffer { 14 | if payload == nil { 15 | return nil 16 | } 17 | return &ConcurrentBuffer{payload, &sync.Mutex{}} 18 | } 19 | 20 | func (b *ConcurrentBuffer) Write(buf []byte) (int, error) { 21 | b.Mutex.Lock() 22 | defer b.Mutex.Unlock() 23 | return b.Buffer.Write(buf) 24 | } 25 | 26 | func (b *ConcurrentBuffer) Read(buf []byte) (int, error) { 27 | b.Mutex.Lock() 28 | defer b.Mutex.Unlock() 29 | return b.Buffer.Read(buf) 30 | } 31 | 32 | func (b *ConcurrentBuffer) Reset() { 33 | b.Mutex.Lock() 34 | defer b.Mutex.Unlock() 35 | b.Buffer.Reset() 36 | } 37 | -------------------------------------------------------------------------------- /depot/log_streamer/concurrent_buffer_test.go: -------------------------------------------------------------------------------- 1 | package log_streamer_test 2 | 3 | import ( 4 | "bytes" 5 | "io" 6 | 7 | "code.cloudfoundry.org/executor/depot/log_streamer" 8 | 9 | . "github.com/onsi/ginkgo/v2" 10 | . "github.com/onsi/gomega" 11 | ) 12 | 13 | var _ = Describe("concurrent buffer", func() { 14 | Describe("NewConcurrentBuffer", func() { 15 | It("creates a new concurrent buffer out of the given payload", func() { 16 | payload := bytes.NewBuffer([]byte{3, 4, 5}) 17 | content, err := io.ReadAll(log_streamer.NewConcurrentBuffer(payload)) 18 | Expect(err).NotTo(HaveOccurred()) 19 | Expect(content).To(Equal([]byte{3, 4, 5})) 20 | }) 21 | 22 | It("return nil if the payload is nil", func() { 23 | Expect(log_streamer.NewConcurrentBuffer(nil)).To(BeNil()) 24 | }) 25 | }) 26 | 27 | Describe("Write", func() { 28 | var payload *bytes.Buffer 29 | var concurrentBuffer *log_streamer.ConcurrentBuffer 30 | 31 | BeforeEach(func() { 32 | payload = new(bytes.Buffer) 33 | concurrentBuffer = log_streamer.NewConcurrentBuffer(payload) 34 | }) 35 | 36 | It("writes stdout to the buffer", func() { 37 | concurrentBuffer.Write([]byte("hello")) 38 | 39 | output := make([]byte, 5) 40 | _, err := payload.Read(output) 41 | Expect(err).NotTo(HaveOccurred()) 42 | Expect(output).To(Equal([]byte("hello"))) 43 | }) 44 | }) 45 | 46 | Describe("Read", func() { 47 | var payload *bytes.Buffer 48 | var concurrentBuffer *log_streamer.ConcurrentBuffer 49 | 50 | BeforeEach(func() { 51 | payload = new(bytes.Buffer) 52 | concurrentBuffer = log_streamer.NewConcurrentBuffer(payload) 53 | }) 54 | 55 | It("writes stderr to the buffer", func() { 56 | payload.Write([]byte("hello")) 57 | 58 | output := make([]byte, 5) 59 | _, err := concurrentBuffer.Read(output) 60 | Expect(err).NotTo(HaveOccurred()) 61 | Expect(output).To(Equal([]byte("hello"))) 62 | }) 63 | }) 64 | 65 | Describe("Reset", func() { 66 | var payload *bytes.Buffer 67 | var concurrentBuffer *log_streamer.ConcurrentBuffer 68 | 69 | BeforeEach(func() { 70 | payload = new(bytes.Buffer) 71 | concurrentBuffer = log_streamer.NewConcurrentBuffer(payload) 72 | }) 73 | 74 | It("writes stderr to the buffer", func() { 75 | payload.Write([]byte("hello")) 76 | 77 | concurrentBuffer.Reset() 78 | 79 | output := make([]byte, 5) 80 | _, err := payload.Read(output) 81 | Expect(err).To(HaveOccurred()) 82 | Expect(err).To(MatchError(io.EOF)) 83 | }) 84 | }) 85 | 86 | Describe("concurrency test", func() { 87 | var payload *bytes.Buffer 88 | var concurrentBuffer *log_streamer.ConcurrentBuffer 89 | 90 | BeforeEach(func() { 91 | payload = new(bytes.Buffer) 92 | concurrentBuffer = log_streamer.NewConcurrentBuffer(payload) 93 | }) 94 | 95 | // should be run with -race 96 | It("successfully serializes reads and writes", func() { 97 | 98 | _, err := concurrentBuffer.Write([]byte("hello")) 99 | Expect(err).NotTo(HaveOccurred()) 100 | 101 | go func() { 102 | concurrentBuffer.Reset() 103 | _, err := concurrentBuffer.Write([]byte("green")) 104 | Expect(err).NotTo(HaveOccurred()) 105 | }() 106 | 107 | Eventually(func() []byte { 108 | output := make([]byte, 5) 109 | _, _ = concurrentBuffer.Read(output) 110 | return output 111 | }).Should(Equal([]byte("green"))) 112 | }) 113 | }) 114 | }) 115 | -------------------------------------------------------------------------------- /depot/log_streamer/fake_log_streamer/constructor.go: -------------------------------------------------------------------------------- 1 | package fake_log_streamer 2 | 3 | import "github.com/onsi/gomega/gbytes" 4 | 5 | func NewFakeLogStreamer() *FakeLogStreamer { 6 | fakeStreamer := new(FakeLogStreamer) 7 | 8 | stdoutBuffer := gbytes.NewBuffer() 9 | stderrBuffer := gbytes.NewBuffer() 10 | fakeStreamer.StdoutReturns(stdoutBuffer) 11 | fakeStreamer.StderrReturns(stderrBuffer) 12 | fakeStreamer.WithSourceReturns(fakeStreamer) 13 | 14 | return fakeStreamer 15 | } 16 | -------------------------------------------------------------------------------- /depot/log_streamer/fake_log_streamer/package.go: -------------------------------------------------------------------------------- 1 | package fake_log_streamer // import "code.cloudfoundry.org/executor/depot/log_streamer/fake_log_streamer" 2 | -------------------------------------------------------------------------------- /depot/log_streamer/log_streamer.go: -------------------------------------------------------------------------------- 1 | package log_streamer 2 | 3 | import ( 4 | "context" 5 | "io" 6 | "time" 7 | 8 | loggingclient "code.cloudfoundry.org/diego-logging-client" 9 | "code.cloudfoundry.org/executor" 10 | "code.cloudfoundry.org/go-loggregator/v9/rpc/loggregator_v2" 11 | ) 12 | 13 | const ( 14 | MAX_MESSAGE_SIZE = 61440 15 | 16 | DefaultLogSource = "LOG" 17 | ) 18 | 19 | //go:generate counterfeiter -o fake_log_streamer/fake_log_streamer.go . LogStreamer 20 | type LogStreamer interface { 21 | Stdout() io.Writer 22 | Stderr() io.Writer 23 | 24 | UpdateTags(map[string]string) 25 | Flush() 26 | 27 | WithSource(sourceName string) LogStreamer 28 | SourceName() string 29 | 30 | Stop() 31 | } 32 | 33 | type logStreamer struct { 34 | ctx context.Context 35 | cancelFunc context.CancelFunc 36 | stdout *streamDestination 37 | stderr *streamDestination 38 | } 39 | 40 | func New(config executor.LogConfig, metronClient loggingclient.IngressClient, maxLogLinesPerSecond int, maxLogBytesPerSecond int64, metricReportInterval time.Duration) LogStreamer { 41 | if config.Guid == "" { 42 | return noopStreamer{} 43 | } 44 | 45 | sourceName, tags := config.GetSourceNameAndTagsForLogging() 46 | 47 | ctx, cancelFunc := context.WithCancel(context.Background()) 48 | logRateLimiter := NewLogRateLimiter(ctx, metronClient, tags, maxLogLinesPerSecond, maxLogBytesPerSecond, metricReportInterval) 49 | 50 | return &logStreamer{ 51 | ctx: ctx, 52 | cancelFunc: cancelFunc, 53 | stdout: newStreamDestination( 54 | ctx, 55 | sourceName, 56 | tags, 57 | loggregator_v2.Log_OUT, 58 | metronClient, 59 | logRateLimiter, 60 | ), 61 | 62 | stderr: newStreamDestination( 63 | ctx, 64 | sourceName, 65 | tags, 66 | loggregator_v2.Log_ERR, 67 | metronClient, 68 | logRateLimiter, 69 | ), 70 | } 71 | } 72 | 73 | func (e *logStreamer) Stdout() io.Writer { 74 | return e.stdout 75 | } 76 | 77 | func (e *logStreamer) Stderr() io.Writer { 78 | return e.stderr 79 | } 80 | 81 | func (e *logStreamer) UpdateTags(tags map[string]string) { 82 | e.stdout.updateTags(tags) 83 | e.stderr.updateTags(tags) 84 | } 85 | 86 | func (e *logStreamer) Flush() { 87 | e.stdout.lockAndFlush() 88 | e.stderr.lockAndFlush() 89 | } 90 | 91 | func (e *logStreamer) WithSource(sourceName string) LogStreamer { 92 | if sourceName == "" { 93 | sourceName = e.SourceName() 94 | } 95 | 96 | ctx, cancelFunc := context.WithCancel(e.ctx) 97 | 98 | return &logStreamer{ 99 | ctx: ctx, 100 | cancelFunc: cancelFunc, 101 | stdout: e.stdout.withSource(ctx, sourceName), 102 | stderr: e.stderr.withSource(ctx, sourceName), 103 | } 104 | } 105 | 106 | func (e *logStreamer) SourceName() string { 107 | return e.stdout.sourceName 108 | } 109 | 110 | func (e *logStreamer) Stop() { 111 | e.cancelFunc() 112 | } 113 | -------------------------------------------------------------------------------- /depot/log_streamer/log_streamer_suite_test.go: -------------------------------------------------------------------------------- 1 | package log_streamer_test 2 | 3 | import ( 4 | . "github.com/onsi/ginkgo/v2" 5 | . "github.com/onsi/gomega" 6 | 7 | "testing" 8 | ) 9 | 10 | func TestLogStreamer(t *testing.T) { 11 | RegisterFailHandler(Fail) 12 | RunSpecs(t, "Log Streamer Suite") 13 | } 14 | -------------------------------------------------------------------------------- /depot/log_streamer/noop_streamer.go: -------------------------------------------------------------------------------- 1 | package log_streamer 2 | 3 | import ( 4 | "io" 5 | ) 6 | 7 | type noopStreamer struct{} 8 | 9 | func NewNoopStreamer() LogStreamer { 10 | return noopStreamer{} 11 | } 12 | 13 | func (noopStreamer) Stdout() io.Writer { return io.Discard } 14 | func (noopStreamer) Stderr() io.Writer { return io.Discard } 15 | func (noopStreamer) Flush() {} 16 | func (noopStreamer) UpdateTags(tags map[string]string) {} 17 | 18 | func (noopStreamer) WithSource(sourceName string) LogStreamer { 19 | return noopStreamer{} 20 | } 21 | func (noopStreamer) SourceName() string { return DefaultLogSource } 22 | func (noopStreamer) Stop() {} 23 | -------------------------------------------------------------------------------- /depot/log_streamer/package.go: -------------------------------------------------------------------------------- 1 | package log_streamer // import "code.cloudfoundry.org/executor/depot/log_streamer" 2 | -------------------------------------------------------------------------------- /depot/metrics/metrics_suite_test.go: -------------------------------------------------------------------------------- 1 | package metrics_test 2 | 3 | import ( 4 | . "github.com/onsi/ginkgo/v2" 5 | . "github.com/onsi/gomega" 6 | 7 | "testing" 8 | ) 9 | 10 | func TestMetrics(t *testing.T) { 11 | RegisterFailHandler(Fail) 12 | RunSpecs(t, "Metrics Suite") 13 | } 14 | -------------------------------------------------------------------------------- /depot/metrics/package.go: -------------------------------------------------------------------------------- 1 | package metrics // import "code.cloudfoundry.org/executor/depot/metrics" 2 | -------------------------------------------------------------------------------- /depot/package.go: -------------------------------------------------------------------------------- 1 | package depot // import "code.cloudfoundry.org/executor/depot" 2 | -------------------------------------------------------------------------------- /depot/steps/background_step.go: -------------------------------------------------------------------------------- 1 | package steps 2 | 3 | import ( 4 | "os" 5 | 6 | "code.cloudfoundry.org/lager/v3" 7 | "github.com/tedsuo/ifrit" 8 | ) 9 | 10 | type backgroundStep struct { 11 | substep ifrit.Runner 12 | logger lager.Logger 13 | } 14 | 15 | func NewBackground(substep ifrit.Runner, logger lager.Logger) ifrit.Runner { 16 | logger = logger.Session("background-step") 17 | return &backgroundStep{ 18 | substep: substep, 19 | logger: logger, 20 | } 21 | } 22 | 23 | func (step *backgroundStep) Run(signals <-chan os.Signal, ready chan<- struct{}) error { 24 | errCh := make(chan error, 1) 25 | go func() { 26 | errCh <- step.substep.Run(make(chan os.Signal, 1), ready) 27 | }() 28 | 29 | select { 30 | case err := <-errCh: 31 | if err != nil { 32 | step.logger.Info("failed", lager.Data{ 33 | "error": err.Error(), 34 | }) 35 | } 36 | return err 37 | case <-signals: 38 | step.logger.Info("detaching-from-substep") 39 | return nil 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /depot/steps/background_step_test.go: -------------------------------------------------------------------------------- 1 | package steps_test 2 | 3 | import ( 4 | "errors" 5 | "os" 6 | 7 | "code.cloudfoundry.org/executor/depot/steps" 8 | "code.cloudfoundry.org/lager/v3/lagertest" 9 | 10 | . "github.com/onsi/ginkgo/v2" 11 | . "github.com/onsi/gomega" 12 | "github.com/tedsuo/ifrit" 13 | fake_runner "github.com/tedsuo/ifrit/fake_runner_v2" 14 | ) 15 | 16 | var _ = Describe("BackgroundStep", func() { 17 | var ( 18 | substepRunError error 19 | substep *fake_runner.TestRunner 20 | logger *lagertest.TestLogger 21 | process ifrit.Process 22 | ) 23 | 24 | BeforeEach(func() { 25 | logger = lagertest.NewTestLogger("test") 26 | substep = fake_runner.NewTestRunner() 27 | process = ifrit.Background(steps.NewBackground(substep, logger)) 28 | }) 29 | 30 | Describe("Run", func() { 31 | Context("when the substep exits", func() { 32 | JustBeforeEach(func() { 33 | substep.TriggerExit(substepRunError) 34 | }) 35 | 36 | Context("when the substep returns an error", func() { 37 | BeforeEach(func() { 38 | substepRunError = errors.New("some error") 39 | }) 40 | 41 | It("performs the substep", func() { 42 | Eventually(substep.RunCallCount).Should(Equal(1)) 43 | }) 44 | 45 | It("returns this error", func() { 46 | Eventually(process.Wait()).Should(Receive(Equal(substepRunError))) 47 | }) 48 | }) 49 | 50 | Context("when the substep does not error", func() { 51 | BeforeEach(func() { 52 | substepRunError = nil 53 | }) 54 | 55 | It("performs the substep", func() { 56 | Eventually(substep.RunCallCount).Should(Equal(1)) 57 | }) 58 | 59 | It("does not error", func() { 60 | Eventually(process.Wait()).Should(Receive(BeNil())) 61 | }) 62 | }) 63 | }) 64 | 65 | Context("when the substep does not exit", func() { 66 | AfterEach(func() { 67 | substep.EnsureExit() 68 | }) 69 | 70 | It("does not exit", func() { 71 | Consistently(process.Wait()).ShouldNot(Receive()) 72 | }) 73 | }) 74 | 75 | Context("readiness", func() { 76 | AfterEach(func() { 77 | substep.EnsureExit() 78 | }) 79 | 80 | It("becomes ready when the substep is ready", func() { 81 | Consistently(process.Ready()).ShouldNot(BeClosed()) 82 | substep.TriggerReady() 83 | Eventually(process.Ready()).Should(BeClosed()) 84 | }) 85 | }) 86 | }) 87 | 88 | Describe("Signalling", func() { 89 | AfterEach(func() { 90 | substep.EnsureExit() 91 | }) 92 | 93 | It("never signals the substep", func() { 94 | Eventually(substep.RunCallCount).Should(Equal(1)) 95 | process.Signal(os.Interrupt) 96 | Consistently(substep.WaitForCall()).ShouldNot(Receive()) 97 | }) 98 | }) 99 | }) 100 | -------------------------------------------------------------------------------- /depot/steps/codependent_step.go: -------------------------------------------------------------------------------- 1 | package steps 2 | 3 | import ( 4 | "errors" 5 | "os" 6 | 7 | "github.com/hashicorp/go-multierror" 8 | "github.com/tedsuo/ifrit" 9 | ) 10 | 11 | var CodependentStepExitedError = errors.New("Codependent step exited") 12 | 13 | type codependentStep struct { 14 | substeps []ifrit.Runner 15 | errorOnExit bool 16 | cancelOthersOnExit bool 17 | } 18 | 19 | func NewCodependent(substeps []ifrit.Runner, errorOnExit bool, cancelOthersOnExit bool) ifrit.Runner { 20 | return &codependentStep{ 21 | substeps: substeps, 22 | errorOnExit: errorOnExit, 23 | cancelOthersOnExit: cancelOthersOnExit, 24 | } 25 | } 26 | 27 | func (step *codependentStep) Run(signals <-chan os.Signal, ready chan<- struct{}) error { 28 | errCh := make(chan error, len(step.substeps)) 29 | 30 | var subProcesses []ifrit.Process 31 | for _, subStep := range step.substeps { 32 | subProcess := ifrit.Background(subStep) 33 | subProcesses = append(subProcesses, subProcess) 34 | go func() { 35 | err := <-subProcess.Wait() 36 | errCh <- err 37 | }() 38 | } 39 | 40 | done := make(chan struct{}) 41 | defer close(done) 42 | 43 | go waitForSignal(done, signals, subProcesses) 44 | go waitForChildrenToBeReady(done, subProcesses, ready) 45 | 46 | aggregate := &multierror.Error{} 47 | aggregate.ErrorFormat = multiErrorFormat 48 | 49 | var cancelled bool 50 | 51 | for range subProcesses { 52 | err := <-errCh 53 | if step.errorOnExit && err == nil { 54 | err = CodependentStepExitedError 55 | } 56 | 57 | if step.cancelOthersOnExit && err == nil { 58 | if !cancelled { 59 | cancelled = true 60 | cancel(subProcesses, os.Interrupt) 61 | } 62 | } 63 | 64 | if err != nil { 65 | aggregate = multierror.Append(aggregate, err) 66 | 67 | if !cancelled { 68 | cancelled = true 69 | cancel(subProcesses, os.Interrupt) 70 | } 71 | } 72 | } 73 | 74 | return aggregate.ErrorOrNil() 75 | } 76 | -------------------------------------------------------------------------------- /depot/steps/consistently_succeeds_step.go: -------------------------------------------------------------------------------- 1 | package steps 2 | 3 | import ( 4 | "os" 5 | "time" 6 | 7 | "code.cloudfoundry.org/clock" 8 | "github.com/tedsuo/ifrit" 9 | ) 10 | 11 | type consistentlySucceedsStep struct { 12 | create func() ifrit.Runner 13 | clock clock.Clock 14 | frequency time.Duration 15 | } 16 | 17 | // TODO: use a workpool when running the substep 18 | func NewConsistentlySucceedsStep(create func() ifrit.Runner, frequency time.Duration, clock clock.Clock) ifrit.Runner { 19 | return &consistentlySucceedsStep{ 20 | create: create, 21 | frequency: frequency, 22 | clock: clock, 23 | } 24 | } 25 | 26 | func (step *consistentlySucceedsStep) Run(signals <-chan os.Signal, ready chan<- struct{}) error { 27 | t := step.clock.NewTimer(step.frequency) 28 | 29 | close(ready) 30 | 31 | for { 32 | select { 33 | case <-signals: 34 | return new(CancelledError) 35 | case <-t.C(): 36 | } 37 | 38 | consistentStep := step.create() 39 | 40 | process := ifrit.Background(consistentStep) 41 | 42 | select { 43 | case err := <-process.Wait(): 44 | if err != nil { 45 | return err 46 | } 47 | case s := <-signals: 48 | process.Signal(s) 49 | return <-process.Wait() 50 | } 51 | 52 | t.Reset(step.frequency) 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /depot/steps/consistently_succeeds_step_test.go: -------------------------------------------------------------------------------- 1 | package steps_test 2 | 3 | import ( 4 | "errors" 5 | "os" 6 | "time" 7 | 8 | "code.cloudfoundry.org/clock/fakeclock" 9 | "code.cloudfoundry.org/executor/depot/steps" 10 | 11 | . "github.com/onsi/ginkgo/v2" 12 | . "github.com/onsi/gomega" 13 | "github.com/tedsuo/ifrit" 14 | fake_runner "github.com/tedsuo/ifrit/fake_runner_v2" 15 | ) 16 | 17 | var _ = Describe("ConsistentlySucceedsStep", func() { 18 | var ( 19 | step ifrit.Runner 20 | process ifrit.Process 21 | 22 | fakeRunner *fake_runner.TestRunner 23 | fakeClock *fakeclock.FakeClock 24 | ) 25 | 26 | BeforeEach(func() { 27 | fakeClock = fakeclock.NewFakeClock(time.Now()) 28 | fakeRunner = fake_runner.NewTestRunner() 29 | 30 | step = steps.NewConsistentlySucceedsStep(func() ifrit.Runner { return fakeRunner }, time.Second, fakeClock) 31 | }) 32 | 33 | JustBeforeEach(func() { 34 | process = ifrit.Background(step) 35 | }) 36 | 37 | Context("when the process is started", func() { 38 | AfterEach(func() { 39 | fakeClock.WaitForWatcherAndIncrement(time.Second) 40 | fakeRunner.TriggerExit(errors.New("boooom!")) 41 | }) 42 | 43 | It("should not exit", func() { 44 | Consistently(process.Wait()).ShouldNot(Receive(BeNil())) 45 | }) 46 | 47 | It("does not perform the substep initially", func() { 48 | Consistently(fakeRunner.RunCallCount).Should(BeZero()) 49 | }) 50 | 51 | It("becomes ready immediately", func() { 52 | Eventually(process.Ready()).Should(BeClosed()) 53 | }) 54 | }) 55 | 56 | Context("when the step is cancelled", func() { 57 | JustBeforeEach(func() { 58 | process.Signal(os.Interrupt) 59 | }) 60 | 61 | It("cancels the substep", func() { 62 | Eventually(process.Wait()).Should(Receive(MatchError(new(steps.CancelledError)))) 63 | }) 64 | }) 65 | 66 | Context("when the step is stuck", func() { 67 | Context("and the step is cancelled", func() { 68 | JustBeforeEach(func() { 69 | fakeClock.WaitForWatcherAndIncrement(time.Second) 70 | Eventually(fakeRunner.RunCallCount).Should(Equal(1)) 71 | process.Signal(os.Interrupt) 72 | }) 73 | 74 | It("cancels the substep", func() { 75 | signals := fakeRunner.WaitForCall() 76 | Eventually(signals).Should(Receive()) 77 | fakeRunner.TriggerExit(errors.New("BOOOM")) 78 | Eventually(process.Wait()).Should(Receive(MatchError("BOOOM"))) 79 | }) 80 | }) 81 | }) 82 | 83 | Context("when the step is succeeding", func() { 84 | JustBeforeEach(func() { 85 | fakeClock.WaitForWatcherAndIncrement(time.Second) 86 | Eventually(fakeRunner.RunCallCount).Should(Equal(1)) 87 | fakeRunner.TriggerExit(nil) 88 | }) 89 | 90 | It("retries after the timeout has elapsed", func() { 91 | fakeClock.WaitForWatcherAndIncrement(time.Second) 92 | Eventually(fakeRunner.RunCallCount).Should(Equal(2)) 93 | fakeRunner.TriggerExit(errors.New("boooom!")) 94 | }) 95 | 96 | Context("when it later fails", func() { 97 | JustBeforeEach(func() { 98 | fakeClock.WaitForWatcherAndIncrement(time.Second) 99 | Eventually(fakeRunner.RunCallCount).Should(Equal(2)) 100 | fakeRunner.TriggerExit(errors.New("BOOOM")) 101 | }) 102 | 103 | It("should fail", func() { 104 | Eventually(process.Wait()).Should(Receive(MatchError("BOOOM"))) 105 | }) 106 | }) 107 | }) 108 | }) 109 | -------------------------------------------------------------------------------- /depot/steps/emit_check_failure_metric_step.go: -------------------------------------------------------------------------------- 1 | package steps 2 | 3 | import ( 4 | "os" 5 | 6 | loggingclient "code.cloudfoundry.org/diego-logging-client" 7 | "code.cloudfoundry.org/executor" 8 | "github.com/tedsuo/ifrit" 9 | ) 10 | 11 | type emitCheckFailureMetricStep struct { 12 | checkStep ifrit.Runner 13 | checkProtocol executor.CheckProtocol 14 | checkType executor.HealthcheckType 15 | metronClient loggingclient.IngressClient 16 | } 17 | 18 | const ( 19 | CheckFailedCount = "ChecksFailedCount" 20 | ) 21 | 22 | func NewEmitCheckFailureMetricStep( 23 | checkStep ifrit.Runner, 24 | checkProtocol executor.CheckProtocol, 25 | checkType executor.HealthcheckType, 26 | metronClient loggingclient.IngressClient) ifrit.Runner { 27 | return &emitCheckFailureMetricStep{ 28 | checkStep: checkStep, 29 | checkProtocol: checkProtocol, 30 | checkType: checkType, 31 | metronClient: metronClient, 32 | } 33 | } 34 | 35 | func (step *emitCheckFailureMetricStep) Run(signals <-chan os.Signal, ready chan<- struct{}) error { 36 | if step.checkStep == nil { 37 | return nil 38 | } 39 | 40 | checkProccess := ifrit.Background(step.checkStep) 41 | 42 | done := make(chan struct{}) 43 | defer close(done) 44 | go waitForReadiness(checkProccess, ready, done) 45 | 46 | select { 47 | case err := <-checkProccess.Wait(): 48 | if err != nil { 49 | step.emitFailureMetric() 50 | } 51 | return err 52 | case s := <-signals: 53 | checkProccess.Signal(s) 54 | return <-checkProccess.Wait() 55 | } 56 | } 57 | 58 | func (step *emitCheckFailureMetricStep) emitFailureMetric() { 59 | if step.checkType != executor.IsLivenessCheck { 60 | return 61 | } 62 | 63 | if step.checkProtocol == executor.TCPCheck { 64 | httpMetricName := "TCPLivenessChecksFailedCount" 65 | go step.metronClient.IncrementCounter(httpMetricName) 66 | 67 | } else if step.checkProtocol == executor.HTTPCheck { 68 | tcpMetricName := "HTTPLivenessChecksFailedCount" 69 | go step.metronClient.IncrementCounter(tcpMetricName) 70 | } 71 | } 72 | 73 | func waitForReadiness(p ifrit.Process, ready chan<- struct{}, done <-chan struct{}) { 74 | select { 75 | case <-p.Ready(): 76 | close(ready) 77 | case <-done: 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /depot/steps/emit_progress_step.go: -------------------------------------------------------------------------------- 1 | package steps 2 | 3 | import ( 4 | "os" 5 | 6 | "code.cloudfoundry.org/executor/depot/log_streamer" 7 | "github.com/tedsuo/ifrit" 8 | 9 | "code.cloudfoundry.org/lager/v3" 10 | ) 11 | 12 | type emitProgressStep struct { 13 | substep ifrit.Runner 14 | logger lager.Logger 15 | startMessage string 16 | successMessage string 17 | failureMessage string 18 | streamer log_streamer.LogStreamer 19 | } 20 | 21 | func NewEmitProgress( 22 | substep ifrit.Runner, 23 | startMessage, 24 | successMessage, 25 | failureMessage string, 26 | streamer log_streamer.LogStreamer, 27 | logger lager.Logger, 28 | ) *emitProgressStep { 29 | logger = logger.Session("emit-progress-step") 30 | return &emitProgressStep{ 31 | substep: substep, 32 | logger: logger, 33 | startMessage: startMessage, 34 | successMessage: successMessage, 35 | failureMessage: failureMessage, 36 | streamer: streamer, 37 | } 38 | } 39 | 40 | func (step *emitProgressStep) Run(signals <-chan os.Signal, ready chan<- struct{}) error { 41 | if step.startMessage != "" { 42 | _, writeErr := step.streamer.Stdout().Write([]byte(step.startMessage + "\n")) 43 | if writeErr != nil { 44 | step.logger.Debug("failed-writing-to-stdout", lager.Data{"error": writeErr}) 45 | } 46 | } 47 | 48 | err := step.substep.Run(signals, ready) 49 | 50 | if err != nil { 51 | if step.failureMessage != "" { 52 | _, writeErr := step.streamer.Stderr().Write([]byte(step.failureMessage)) 53 | if writeErr != nil { 54 | step.logger.Debug("failed-writing-to-stderr", lager.Data{"error": writeErr}) 55 | } 56 | 57 | if emittableError, ok := err.(*EmittableError); ok { 58 | _, writeErr := step.streamer.Stderr().Write([]byte(": ")) 59 | if writeErr != nil { 60 | step.logger.Debug("failed-writing-to-stderr", lager.Data{"error": writeErr}) 61 | } 62 | _, writeErr = step.streamer.Stderr().Write([]byte(emittableError.Error())) 63 | if writeErr != nil { 64 | step.logger.Debug("failed-writing-to-stderr", lager.Data{"error": writeErr}) 65 | } 66 | 67 | wrappedMessage := "" 68 | if emittableError.WrappedError() != nil { 69 | wrappedMessage = emittableError.WrappedError().Error() 70 | } 71 | 72 | step.logger.Info("errored", lager.Data{ 73 | "wrapped-error": wrappedMessage, 74 | "message-emitted": emittableError.Error(), 75 | }) 76 | } 77 | 78 | _, writeErr = step.streamer.Stderr().Write([]byte("\n")) 79 | if writeErr != nil { 80 | step.logger.Debug("failed-writing-to-stderr", lager.Data{"error": writeErr}) 81 | } 82 | } 83 | } else { 84 | if step.successMessage != "" { 85 | _, writeErr := step.streamer.Stdout().Write([]byte(step.successMessage + "\n")) 86 | if writeErr != nil { 87 | step.logger.Debug("failed-writing-to-stdout", lager.Data{"error": writeErr}) 88 | } 89 | } 90 | } 91 | 92 | return err 93 | } 94 | -------------------------------------------------------------------------------- /depot/steps/emittable_error.go: -------------------------------------------------------------------------------- 1 | package steps 2 | 3 | import "fmt" 4 | 5 | type EmittableError struct { 6 | msg string 7 | wrappedError error 8 | } 9 | 10 | func NewEmittableError(wrappedError error, message string, args ...interface{}) *EmittableError { 11 | msg := message 12 | if len(args) > 0 { 13 | msg = fmt.Sprintf(message, args...) 14 | } 15 | 16 | return &EmittableError{ 17 | wrappedError: wrappedError, 18 | msg: msg, 19 | } 20 | } 21 | 22 | func (e *EmittableError) Error() string { 23 | return e.msg 24 | } 25 | 26 | func (e *EmittableError) WrappedError() error { 27 | return e.wrappedError 28 | } 29 | -------------------------------------------------------------------------------- /depot/steps/emittable_error_test.go: -------------------------------------------------------------------------------- 1 | package steps_test 2 | 3 | import ( 4 | "errors" 5 | 6 | "code.cloudfoundry.org/executor/depot/steps" 7 | 8 | . "github.com/onsi/ginkgo/v2" 9 | . "github.com/onsi/gomega" 10 | ) 11 | 12 | var _ = Describe("EmittableError", func() { 13 | wrappedError := errors.New("the wrapped error") 14 | 15 | It("should satisfy the error interface", func() { 16 | err := steps.NewEmittableError(wrappedError, "Fancy") 17 | Expect(err).To(HaveOccurred()) 18 | }) 19 | 20 | Describe("WrappedError", func() { 21 | It("returns the wrapped error message", func() { 22 | err := steps.NewEmittableError(wrappedError, "Fancy emittable message") 23 | Expect(err.WrappedError()).To(Equal(wrappedError)) 24 | }) 25 | 26 | Context("when the wrapped error is nil", func() { 27 | It("should not blow up", func() { 28 | err := steps.NewEmittableError(nil, "Fancy emittable message") 29 | Expect(err.WrappedError()).To(BeNil()) 30 | }) 31 | }) 32 | }) 33 | 34 | Describe("Error", func() { 35 | Context("with no format args", func() { 36 | It("should just be the message", func() { 37 | args := []interface{}{} 38 | Expect(steps.NewEmittableError(wrappedError, "Fancy %s %d", args...).Error()).To(Equal("Fancy %s %d")) 39 | }) 40 | }) 41 | 42 | Context("with format args", func() { 43 | It("should Sprintf", func() { 44 | Expect(steps.NewEmittableError(wrappedError, "Fancy %s %d", "hi", 3).Error()).To(Equal("Fancy hi 3")) 45 | }) 46 | }) 47 | }) 48 | }) 49 | -------------------------------------------------------------------------------- /depot/steps/errors.go: -------------------------------------------------------------------------------- 1 | package steps 2 | 3 | import "fmt" 4 | 5 | type IsDisplayableError interface { 6 | IsDisplayable() bool 7 | } 8 | 9 | type CancelledError struct{} 10 | 11 | func (e *CancelledError) Error() string { 12 | return "cancelled" 13 | } 14 | 15 | func (e *CancelledError) IsDisplayable() bool { 16 | return false 17 | } 18 | 19 | type ExceededGracefulShutdownIntervalError struct{} 20 | 21 | func (e *ExceededGracefulShutdownIntervalError) Error() string { 22 | return "exceeded graceful shutdown interval" 23 | } 24 | 25 | func (e *ExceededGracefulShutdownIntervalError) IsDisplayable() bool { 26 | return false 27 | } 28 | 29 | type ExitTimeoutError struct{} 30 | 31 | func (e *ExitTimeoutError) Error() string { 32 | return "process did not exit" 33 | } 34 | 35 | func multiErrorFormat(errs []error) string { 36 | var errStr string 37 | for _, e := range errs { 38 | if displayableErr, ok := e.(IsDisplayableError); ok { 39 | if !displayableErr.IsDisplayable() { 40 | continue 41 | } 42 | } 43 | if errStr == "" { 44 | errStr = e.Error() 45 | } else if e.Error() != "" { 46 | errStr = fmt.Sprintf("%s; %s", errStr, e) 47 | } 48 | } 49 | return errStr 50 | } 51 | -------------------------------------------------------------------------------- /depot/steps/eventually_succeeds_step.go: -------------------------------------------------------------------------------- 1 | package steps 2 | 3 | import ( 4 | "os" 5 | "time" 6 | 7 | "code.cloudfoundry.org/clock" 8 | "github.com/tedsuo/ifrit" 9 | ) 10 | 11 | type eventuallySucceedsStep struct { 12 | create func() ifrit.Runner 13 | frequency, timeout time.Duration 14 | clock clock.Clock 15 | } 16 | 17 | // TODO: use a workpool when running the substep 18 | func NewEventuallySucceedsStep(create func() ifrit.Runner, frequency, timeout time.Duration, clock clock.Clock) ifrit.Runner { 19 | return &eventuallySucceedsStep{ 20 | create: create, 21 | frequency: frequency, 22 | timeout: timeout, 23 | clock: clock, 24 | } 25 | } 26 | 27 | func (step *eventuallySucceedsStep) Run(signals <-chan os.Signal, ready chan<- struct{}) error { 28 | var err error 29 | 30 | close(ready) 31 | 32 | startTime := step.clock.Now() 33 | t := step.clock.NewTimer(step.frequency) 34 | 35 | for { 36 | select { 37 | case <-t.C(): 38 | case <-signals: 39 | return new(CancelledError) 40 | } 41 | 42 | subProcess := ifrit.Background(step.create()) 43 | 44 | select { 45 | case s := <-signals: 46 | subProcess.Signal(s) 47 | return <-subProcess.Wait() 48 | case err = <-subProcess.Wait(): 49 | if err == nil { 50 | return nil 51 | } 52 | } 53 | 54 | if step.timeout > 0 && step.clock.Now().After(startTime.Add(step.timeout)) { 55 | return err 56 | } 57 | 58 | t.Reset(step.frequency) 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /depot/steps/eventually_succeeds_step_test.go: -------------------------------------------------------------------------------- 1 | package steps_test 2 | 3 | import ( 4 | "errors" 5 | "os" 6 | "time" 7 | 8 | "code.cloudfoundry.org/clock/fakeclock" 9 | "code.cloudfoundry.org/executor/depot/steps" 10 | 11 | . "github.com/onsi/ginkgo/v2" 12 | . "github.com/onsi/gomega" 13 | "github.com/tedsuo/ifrit" 14 | fake_runner "github.com/tedsuo/ifrit/fake_runner_v2" 15 | ) 16 | 17 | var _ = Describe("EventuallySucceedsStep", func() { 18 | var ( 19 | step ifrit.Runner 20 | process ifrit.Process 21 | 22 | fakeStep *fake_runner.TestRunner 23 | fakeClock *fakeclock.FakeClock 24 | ) 25 | 26 | BeforeEach(func() { 27 | fakeClock = fakeclock.NewFakeClock(time.Now()) 28 | fakeStep = fake_runner.NewTestRunner() 29 | 30 | step = steps.NewEventuallySucceedsStep(func() ifrit.Runner { return fakeStep }, time.Second, 10*time.Second, fakeClock) 31 | }) 32 | 33 | JustBeforeEach(func() { 34 | process = ifrit.Background(step) 35 | }) 36 | 37 | Context("when the process is started", func() { 38 | AfterEach(func() { 39 | fakeClock.WaitForWatcherAndIncrement(10 * time.Second) 40 | fakeStep.TriggerExit(nil) 41 | }) 42 | 43 | It("should not trigger the substep initially", func() { 44 | Consistently(fakeStep.RunCallCount).Should(BeZero()) 45 | }) 46 | 47 | It("becomes ready immediately", func() { 48 | Eventually(process.Ready()).Should(BeClosed()) 49 | }) 50 | }) 51 | 52 | Context("when the step succeeds", func() { 53 | JustBeforeEach(func() { 54 | fakeClock.WaitForWatcherAndIncrement(time.Second) 55 | fakeStep.TriggerExit(nil) 56 | }) 57 | 58 | It("should exits with no errors", func() { 59 | Eventually(process.Wait()).Should(Receive(BeNil())) 60 | }) 61 | }) 62 | 63 | Context("when the step is stuck", func() { 64 | Context("and the step is signalled", func() { 65 | JustBeforeEach(func() { 66 | fakeClock.WaitForWatcherAndIncrement(time.Second) 67 | Eventually(fakeStep.RunCallCount).Should(Equal(1)) 68 | process.Signal(os.Interrupt) 69 | }) 70 | 71 | It("cancels the substep", func() { 72 | Eventually(fakeStep.WaitForCall()).Should(Receive()) 73 | fakeStep.TriggerExit(errors.New("BOOOOM")) 74 | Eventually(process.Wait()).Should(Receive(MatchError("BOOOOM"))) 75 | }) 76 | }) 77 | }) 78 | 79 | Context("when the step is signalled", func() { 80 | JustBeforeEach(func() { 81 | process.Signal(os.Interrupt) 82 | }) 83 | 84 | It("returns CancelledError", func() { 85 | Eventually(process.Wait()).Should(Receive(MatchError(new(steps.CancelledError)))) 86 | }) 87 | }) 88 | 89 | Context("when the step is failing", func() { 90 | JustBeforeEach(func() { 91 | fakeClock.WaitForWatcherAndIncrement(time.Second) 92 | fakeStep.TriggerExit(errors.New("BOOOOM")) 93 | }) 94 | 95 | It("retries after the timeout has elapsed", func() { 96 | fakeClock.WaitForWatcherAndIncrement(time.Second) 97 | Eventually(fakeStep.RunCallCount).Should(Equal(2)) 98 | fakeStep.TriggerExit(nil) 99 | }) 100 | 101 | Context("and the timeout elapsed", func() { 102 | JustBeforeEach(func() { 103 | Eventually(fakeStep.RunCallCount).Should(Equal(1)) 104 | fakeClock.WaitForWatcherAndIncrement(10 * time.Second) 105 | fakeStep.TriggerExit(errors.New("BOOOOM")) 106 | }) 107 | 108 | It("returns the last error received from the substep", func() { 109 | Eventually(process.Wait()).Should(Receive(MatchError(ContainSubstring("BOOOOM")))) 110 | }) 111 | }) 112 | 113 | Context("when it later succeed", func() { 114 | JustBeforeEach(func() { 115 | Eventually(fakeStep.RunCallCount).Should(Equal(1)) 116 | fakeClock.WaitForWatcherAndIncrement(time.Second) 117 | fakeStep.TriggerExit(nil) 118 | }) 119 | 120 | It("should succeed", func() { 121 | Eventually(process.Wait()).Should(Receive(BeNil())) 122 | }) 123 | }) 124 | }) 125 | }) 126 | -------------------------------------------------------------------------------- /depot/steps/health_check_step.go: -------------------------------------------------------------------------------- 1 | package steps 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "time" 7 | 8 | "code.cloudfoundry.org/clock" 9 | "code.cloudfoundry.org/executor/depot/log_streamer" 10 | "code.cloudfoundry.org/lager/v3" 11 | "github.com/tedsuo/ifrit" 12 | ) 13 | 14 | const ( 15 | startupFailureMessage = "Failed after %s: startup health check never passed.\n" 16 | timeoutCrashReason = "Instance never healthy after %s: %s" 17 | healthcheckNowUnhealthy = "Instance became unhealthy: %s" 18 | ) 19 | 20 | type healthCheckStep struct { 21 | startupCheck ifrit.Runner 22 | livenessCheck ifrit.Runner 23 | 24 | logger lager.Logger 25 | clock clock.Clock 26 | logStreamer log_streamer.LogStreamer 27 | healthCheckStreamer log_streamer.LogStreamer 28 | 29 | startTimeout time.Duration 30 | } 31 | 32 | func NewHealthCheckStep( 33 | startupCheck ifrit.Runner, 34 | livenessCheck ifrit.Runner, 35 | logger lager.Logger, 36 | clock clock.Clock, 37 | logStreamer log_streamer.LogStreamer, 38 | healthcheckStreamer log_streamer.LogStreamer, 39 | startTimeout time.Duration, 40 | ) ifrit.Runner { 41 | logger = logger.Session("health-check-step") 42 | 43 | return &healthCheckStep{ 44 | startupCheck: startupCheck, 45 | livenessCheck: livenessCheck, 46 | logger: logger, 47 | clock: clock, 48 | logStreamer: logStreamer, 49 | healthCheckStreamer: healthcheckStreamer, 50 | startTimeout: startTimeout, 51 | } 52 | } 53 | 54 | func (step *healthCheckStep) Run(signals <-chan os.Signal, ready chan<- struct{}) error { 55 | //TODO: make this use metron agent directly, don't use log streamer, shouldn't be rate limited. 56 | fmt.Fprint(step.logStreamer.Stdout(), "Starting health monitoring of container\n") 57 | 58 | startupProcess := ifrit.Background(step.startupCheck) 59 | 60 | healthCheckStartedTime := time.Now() 61 | 62 | select { 63 | case err := <-startupProcess.Wait(): 64 | if err != nil { 65 | healthCheckFailedTime := time.Since(healthCheckStartedTime).Round(time.Millisecond) 66 | //TODO: make this use metron agent directly, don't use log streamer, shouldn't be rate limited. 67 | fmt.Fprintf(step.healthCheckStreamer.Stderr(), "%s\n", err.Error()) 68 | fmt.Fprintf(step.logStreamer.Stderr(), startupFailureMessage, healthCheckFailedTime) 69 | step.logger.Info("timed-out-before-healthy", lager.Data{ 70 | "step-error": err.Error(), 71 | }) 72 | return NewEmittableError(err, timeoutCrashReason, healthCheckFailedTime, err.Error()) 73 | } 74 | case s := <-signals: 75 | startupProcess.Signal(s) 76 | <-startupProcess.Wait() 77 | return new(CancelledError) 78 | } 79 | 80 | step.logger.Info("transitioned-to-healthy") 81 | //TODO: make this use metron agent directly, don't use log streamer, shouldn't be rate limited. 82 | fmt.Fprint(step.logStreamer.Stdout(), "Container became healthy\n") 83 | close(ready) 84 | 85 | livenessProcess := ifrit.Background(step.livenessCheck) 86 | 87 | select { 88 | case err := <-livenessProcess.Wait(): 89 | step.logger.Info("transitioned-to-unhealthy") 90 | //TODO: make this use metron agent directly, don't use log streamer, shouldn't be rate limited. 91 | fmt.Fprintf(step.healthCheckStreamer.Stderr(), "%s\n", err.Error()) 92 | fmt.Fprint(step.logStreamer.Stderr(), "Container became unhealthy\n") 93 | return NewEmittableError(err, healthcheckNowUnhealthy, err.Error()) 94 | case s := <-signals: 95 | livenessProcess.Signal(s) 96 | <-livenessProcess.Wait() 97 | return new(CancelledError) 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /depot/steps/monitor_step.go: -------------------------------------------------------------------------------- 1 | package steps 2 | 3 | import ( 4 | "time" 5 | 6 | "code.cloudfoundry.org/clock" 7 | "code.cloudfoundry.org/executor/depot/log_streamer" 8 | "code.cloudfoundry.org/lager/v3" 9 | "code.cloudfoundry.org/workpool" 10 | "github.com/tedsuo/ifrit" 11 | ) 12 | 13 | func NewMonitor( 14 | checkFunc func() ifrit.Runner, 15 | logger lager.Logger, 16 | clock clock.Clock, 17 | logStreamer log_streamer.LogStreamer, 18 | startTimeout time.Duration, 19 | healthyInterval time.Duration, 20 | unhealthyInterval time.Duration, 21 | workPool *workpool.WorkPool, 22 | proxyStartupChecks ...ifrit.Runner, 23 | ) ifrit.Runner { 24 | throttledCheckFunc := func() ifrit.Runner { 25 | return NewThrottle(checkFunc(), workPool) 26 | } 27 | 28 | startupCheck := NewEventuallySucceedsStep(throttledCheckFunc, unhealthyInterval, startTimeout, clock) 29 | liveness := NewConsistentlySucceedsStep(throttledCheckFunc, healthyInterval, clock) 30 | 31 | // add the proxy startup checks (if any) 32 | startupCheck = NewParallel(append(proxyStartupChecks, startupCheck)) 33 | 34 | return NewHealthCheckStep(startupCheck, liveness, logger, clock, logStreamer, logStreamer, startTimeout) 35 | } 36 | -------------------------------------------------------------------------------- /depot/steps/output_wrapper_step.go: -------------------------------------------------------------------------------- 1 | package steps 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "os" 7 | "strings" 8 | 9 | "github.com/tedsuo/ifrit" 10 | ) 11 | 12 | type outputWrapperStep struct { 13 | substep ifrit.Runner 14 | prefix string 15 | reader io.Reader 16 | } 17 | 18 | // This step ignores the error from the substep and returns the content of 19 | // Reader as an emittable error. This is used to wrap the output of the 20 | // healthcheck as the error instead of using the exit status or the process 21 | func NewOutputWrapper(substep ifrit.Runner, reader io.Reader) ifrit.Runner { 22 | return NewOutputWrapperWithPrefix(substep, reader, "") 23 | } 24 | 25 | func NewOutputWrapperWithPrefix(substep ifrit.Runner, reader io.Reader, prefix string) ifrit.Runner { 26 | return &outputWrapperStep{ 27 | substep: substep, 28 | reader: reader, 29 | prefix: prefix, 30 | } 31 | } 32 | 33 | func (step *outputWrapperStep) Run(signals <-chan os.Signal, ready chan<- struct{}) error { 34 | subStepErr := step.substep.Run(signals, ready) 35 | 36 | if subStepErr == nil { 37 | return nil 38 | } 39 | 40 | bytes, err := io.ReadAll(step.reader) 41 | if err != nil { 42 | return fmt.Errorf("Error reading from process output buffer: %s", err) 43 | } 44 | 45 | msg := fmt.Sprintf("Failed to invoke process: %s", subStepErr) 46 | 47 | readerErr := string(bytes) 48 | if readerErr != "" { 49 | msg = strings.TrimSpace(readerErr) 50 | } 51 | 52 | if step.prefix != "" { 53 | msg = step.prefix + ": " + msg 54 | } 55 | return NewEmittableError(subStepErr, "%s", msg) 56 | } 57 | -------------------------------------------------------------------------------- /depot/steps/output_wrapper_step_test.go: -------------------------------------------------------------------------------- 1 | package steps_test 2 | 3 | import ( 4 | "bytes" 5 | "errors" 6 | "os" 7 | 8 | "code.cloudfoundry.org/executor/depot/steps" 9 | 10 | . "github.com/onsi/ginkgo/v2" 11 | . "github.com/onsi/gomega" 12 | "github.com/tedsuo/ifrit" 13 | fake_runner "github.com/tedsuo/ifrit/fake_runner_v2" 14 | ) 15 | 16 | var _ = Describe("OutputWrapperStep", func() { 17 | var ( 18 | subStep *fake_runner.TestRunner 19 | step ifrit.Runner 20 | buffer *bytes.Buffer 21 | ) 22 | 23 | BeforeEach(func() { 24 | subStep = fake_runner.NewTestRunner() 25 | buffer = bytes.NewBuffer(nil) 26 | step = steps.NewOutputWrapper(subStep, buffer) 27 | }) 28 | 29 | AfterEach(func() { 30 | subStep.EnsureExit() 31 | }) 32 | 33 | Context("Ready", func() { 34 | It("becomes ready when the substep is ready", func() { 35 | p := ifrit.Background(step) 36 | Consistently(p.Ready()).ShouldNot(BeClosed()) 37 | subStep.TriggerReady() 38 | Eventually(p.Ready()).Should(BeClosed()) 39 | }) 40 | }) 41 | 42 | Context("Run", func() { 43 | It("calls perform on the substep", func() { 44 | ifrit.Background(step) 45 | Eventually(subStep.RunCallCount).Should(Equal(1)) 46 | }) 47 | 48 | Context("when the substep fails", func() { 49 | var ( 50 | errStr string 51 | ) 52 | 53 | BeforeEach(func() { 54 | go subStep.TriggerExit(errors.New("BOOOM!")) 55 | errStr = "error reason" 56 | }) 57 | 58 | JustBeforeEach(func() { 59 | buffer.WriteString(errStr) 60 | }) 61 | 62 | It("wraps the buffer content in an emittable error", func() { 63 | p := ifrit.Background(step) 64 | Eventually(p.Wait()).Should(Receive(MatchError("error reason"))) 65 | }) 66 | 67 | Context("when the output has whitespaces", func() { 68 | BeforeEach(func() { 69 | errStr = "\r\nerror reason\r\n" 70 | }) 71 | 72 | It("trims the extra whitespace", func() { 73 | p := ifrit.Background(step) 74 | Eventually(p.Wait()).Should(Receive(MatchError("error reason"))) 75 | }) 76 | }) 77 | }) 78 | 79 | Context("when the substep is cancelled", func() { 80 | BeforeEach(func() { 81 | go subStep.TriggerExit(new(steps.CancelledError)) 82 | }) 83 | 84 | It("returns the CancelledError error", func() { 85 | p := ifrit.Background(step) 86 | Eventually(p.Wait()).Should(Receive(MatchError(steps.NewEmittableError(new(steps.CancelledError), "Failed to invoke process: cancelled")))) 87 | }) 88 | 89 | Context("and the buffer has data", func() { 90 | BeforeEach(func() { 91 | buffer.WriteString("error reason") 92 | }) 93 | 94 | It("wraps the buffer content in an emittable error", func() { 95 | p := ifrit.Background(step) 96 | Eventually(p.Wait()).Should(Receive(MatchError("error reason"))) 97 | }) 98 | }) 99 | }) 100 | }) 101 | 102 | Context("Signal", func() { 103 | It("calls Signal on the substep", func() { 104 | ch := make(chan struct{}) 105 | defer close(ch) 106 | 107 | p := ifrit.Background(step) 108 | p.Signal(os.Interrupt) 109 | signals := subStep.WaitForCall() 110 | Eventually(signals).Should(Receive()) 111 | }) 112 | }) 113 | }) 114 | -------------------------------------------------------------------------------- /depot/steps/package.go: -------------------------------------------------------------------------------- 1 | package steps // import "code.cloudfoundry.org/executor/depot/steps" 2 | -------------------------------------------------------------------------------- /depot/steps/parallel_step.go: -------------------------------------------------------------------------------- 1 | package steps 2 | 3 | import ( 4 | "os" 5 | 6 | "github.com/hashicorp/go-multierror" 7 | "github.com/tedsuo/ifrit" 8 | ) 9 | 10 | type parallelStep struct { 11 | substeps []ifrit.Runner 12 | } 13 | 14 | func NewParallel(substeps []ifrit.Runner) *parallelStep { 15 | return ¶llelStep{ 16 | substeps: substeps, 17 | } 18 | } 19 | 20 | func (step *parallelStep) Run(signals <-chan os.Signal, ready chan<- struct{}) error { 21 | var subProcesses []ifrit.Process 22 | for _, subStep := range step.substeps { 23 | subProcesses = append(subProcesses, ifrit.Background(subStep)) 24 | } 25 | 26 | done := make(chan struct{}) 27 | defer close(done) 28 | 29 | go waitForChildrenToBeReady(done, subProcesses, ready) 30 | go waitForSignal(done, signals, subProcesses) 31 | 32 | aggregate := &multierror.Error{} 33 | aggregate.ErrorFormat = multiErrorFormat 34 | 35 | for _, subProcess := range subProcesses { 36 | err := <-subProcess.Wait() 37 | if err != nil { 38 | aggregate = multierror.Append(aggregate, err) 39 | } 40 | } 41 | 42 | return aggregate.ErrorOrNil() 43 | } 44 | 45 | func waitForSignal(done <-chan struct{}, signals <-chan os.Signal, ps []ifrit.Process) { 46 | select { 47 | case <-done: 48 | return 49 | case s := <-signals: 50 | cancel(ps, s) 51 | } 52 | } 53 | 54 | func cancel(processes []ifrit.Process, signal os.Signal) { 55 | for _, p := range processes { 56 | p.Signal(signal) 57 | } 58 | } 59 | 60 | func waitForChildrenToBeReady(done <-chan struct{}, ps []ifrit.Process, ready chan<- struct{}) { 61 | for _, p := range ps { 62 | select { 63 | case <-done: 64 | // do not leak goroutine if a subProcess exits before it is ready 65 | return 66 | case <-p.Ready(): 67 | } 68 | } 69 | close(ready) 70 | } 71 | -------------------------------------------------------------------------------- /depot/steps/parallel_step_test.go: -------------------------------------------------------------------------------- 1 | package steps_test 2 | 3 | import ( 4 | "errors" 5 | "os" 6 | 7 | "github.com/hashicorp/go-multierror" 8 | . "github.com/onsi/ginkgo/v2" 9 | . "github.com/onsi/gomega" 10 | "github.com/tedsuo/ifrit" 11 | fake_runner "github.com/tedsuo/ifrit/fake_runner_v2" 12 | 13 | "code.cloudfoundry.org/executor/depot/steps" 14 | ) 15 | 16 | var _ = Describe("ParallelStep", func() { 17 | var ( 18 | step ifrit.Runner 19 | process ifrit.Process 20 | 21 | subStep1 *fake_runner.TestRunner 22 | subStep2 *fake_runner.TestRunner 23 | ) 24 | 25 | BeforeEach(func() { 26 | subStep1 = fake_runner.NewTestRunner() 27 | subStep2 = fake_runner.NewTestRunner() 28 | }) 29 | 30 | JustBeforeEach(func() { 31 | step = steps.NewParallel([]ifrit.Runner{subStep1, subStep2}) 32 | process = ifrit.Background(step) 33 | }) 34 | 35 | AfterEach(func() { 36 | subStep1.EnsureExit() 37 | subStep2.EnsureExit() 38 | }) 39 | 40 | It("performs its substeps in parallel", func() { 41 | Eventually(subStep1.RunCallCount).Should(Equal(1)) 42 | Eventually(subStep2.RunCallCount).Should(Equal(1)) 43 | subStep1.TriggerExit(nil) 44 | subStep2.TriggerExit(nil) 45 | 46 | Eventually(process.Wait()).Should(Receive(BeNil())) 47 | }) 48 | 49 | Context("when multiple substeps fail", func() { 50 | disaster1 := errors.New("oh no") 51 | disaster2 := errors.New("oh my") 52 | 53 | It("joins the error messages with a semicolon", func() { 54 | subStep1.TriggerExit(disaster1) 55 | subStep2.TriggerExit(disaster2) 56 | 57 | var err error 58 | Eventually(process.Wait()).Should(Receive(&err)) 59 | Expect(err).To(HaveOccurred()) 60 | errMsg := err.Error() 61 | Expect(errMsg).NotTo(HavePrefix(";")) 62 | Expect(errMsg).To(ContainSubstring("oh no")) 63 | Expect(errMsg).To(ContainSubstring("oh my")) 64 | Expect(errMsg).To(MatchRegexp(`\w+; \w+`)) 65 | }) 66 | 67 | Context("when step fails with a non displayable error", func() { 68 | It("does not add non displayable error to message", func() { 69 | nonDisplayableErr := new(NonDisplayableError) 70 | subStep1.TriggerExit(nonDisplayableErr) 71 | subStep2.TriggerExit(disaster2) 72 | 73 | var err error 74 | Eventually(process.Wait()).Should(Receive(&err)) 75 | Expect(err).To(HaveOccurred()) 76 | errMsg := err.Error() 77 | Expect(errMsg).NotTo(HavePrefix(";")) 78 | Expect(errMsg).To(ContainSubstring("oh my")) 79 | Expect(errMsg).NotTo(ContainSubstring("some-non-displaybale-error")) 80 | }) 81 | }) 82 | }) 83 | 84 | Context("when first substep fails", func() { 85 | disaster := errors.New("oh no!") 86 | 87 | It("waits for the rest to finish", func() { 88 | subStep1.TriggerExit(disaster) 89 | 90 | Consistently(process.Wait()).ShouldNot(Receive()) 91 | 92 | subStep2.TriggerExit(nil) 93 | 94 | var err error 95 | Eventually(process.Wait()).Should(Receive(&err)) 96 | Expect(err.(*multierror.Error).WrappedErrors()).To(ConsistOf(disaster)) 97 | }) 98 | }) 99 | 100 | Context("when told to cancel", func() { 101 | It("cancels its substeps", func() { 102 | process.Signal(os.Interrupt) 103 | 104 | Eventually(subStep1.WaitForCall()).Should(Receive(Equal(os.Interrupt))) 105 | Eventually(subStep2.WaitForCall()).Should(Receive(Equal(os.Interrupt))) 106 | }) 107 | }) 108 | 109 | Describe("process readiness", func() { 110 | It("does not become ready until its subprocesses are", func() { 111 | Consistently(process.Ready()).ShouldNot(BeClosed()) 112 | 113 | subStep1.TriggerReady() 114 | Consistently(process.Ready()).ShouldNot(BeClosed()) 115 | 116 | subStep2.TriggerReady() 117 | Eventually(process.Ready()).Should(BeClosed()) 118 | }) 119 | 120 | It("never becomes ready if a subprocess exits without becoming ready", func() { 121 | Consistently(process.Ready()).ShouldNot(BeClosed()) 122 | 123 | subStep1.TriggerReady() 124 | Consistently(process.Ready()).ShouldNot(BeClosed()) 125 | 126 | subStep2.TriggerExit(errors.New("some error")) 127 | Consistently(process.Ready()).ShouldNot(BeClosed()) 128 | }) 129 | }) 130 | }) 131 | -------------------------------------------------------------------------------- /depot/steps/readiness_health_check_step.go: -------------------------------------------------------------------------------- 1 | package steps 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | 7 | "code.cloudfoundry.org/executor/depot/log_streamer" 8 | "code.cloudfoundry.org/lager/v3" 9 | "github.com/tedsuo/ifrit" 10 | ) 11 | 12 | type ReadinessState int 13 | 14 | const ( 15 | IsReady ReadinessState = iota 16 | IsNotReady 17 | ) 18 | 19 | type readinessHealthCheckStep struct { 20 | untilReadyCheck ifrit.Runner 21 | untilFailureCheck ifrit.Runner 22 | logger lager.Logger 23 | logStreamer log_streamer.LogStreamer 24 | readinessChan chan ReadinessState 25 | } 26 | 27 | func NewReadinessHealthCheckStep( 28 | untilReadyCheck ifrit.Runner, 29 | untilFailureCheck ifrit.Runner, 30 | logStreamer log_streamer.LogStreamer, 31 | readinessChan chan ReadinessState, 32 | logger lager.Logger, 33 | ) ifrit.Runner { 34 | return &readinessHealthCheckStep{ 35 | untilReadyCheck: untilReadyCheck, 36 | untilFailureCheck: untilFailureCheck, 37 | logStreamer: logStreamer, 38 | readinessChan: readinessChan, 39 | logger: logger, 40 | } 41 | } 42 | 43 | func (step *readinessHealthCheckStep) Run(signals <-chan os.Signal, ready chan<- struct{}) error { 44 | fmt.Fprint(step.logStreamer.Stdout(), "Starting readiness health monitoring of container\n") 45 | close(ready) 46 | 47 | for { 48 | err := step.runUntilReadyProcess(signals) 49 | if err != nil { 50 | return err 51 | } 52 | err = step.runUntilFailureProcess(signals) 53 | if err != nil { 54 | return err 55 | } 56 | } 57 | } 58 | 59 | func (step *readinessHealthCheckStep) runUntilReadyProcess(signals <-chan os.Signal) error { 60 | untilReadyProcess := ifrit.Background(step.untilReadyCheck) 61 | select { 62 | case err := <-untilReadyProcess.Wait(): 63 | if err != nil { 64 | fmt.Fprint(step.logStreamer.Stdout(), "Failed to run the readiness check\n") 65 | return err 66 | } 67 | step.logger.Info("transitioned-to-ready") 68 | step.readinessChan <- IsReady 69 | fmt.Fprint(step.logStreamer.Stdout(), "Container passed the readiness health check. Container marked ready and added to route pool.\n") 70 | return nil 71 | case s := <-signals: 72 | untilReadyProcess.Signal(s) 73 | <-untilReadyProcess.Wait() 74 | return new(CancelledError) 75 | } 76 | } 77 | 78 | func (step *readinessHealthCheckStep) runUntilFailureProcess(signals <-chan os.Signal) error { 79 | untilFailureProcess := ifrit.Background(step.untilFailureCheck) 80 | select { 81 | case err := <-untilFailureProcess.Wait(): 82 | if err != nil { 83 | step.logger.Info("transitioned-to-not-ready") 84 | fmt.Fprint(step.logStreamer.Stdout(), "Container failed the readiness health check. Container marked not ready and removed from route pool.\n") 85 | step.readinessChan <- IsNotReady 86 | return nil 87 | } 88 | step.logger.Error("unexpected-until-failure-check-result", err) 89 | return nil 90 | case s := <-signals: 91 | untilFailureProcess.Signal(s) 92 | <-untilFailureProcess.Wait() 93 | return new(CancelledError) 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /depot/steps/serial_step.go: -------------------------------------------------------------------------------- 1 | package steps 2 | 3 | import ( 4 | "os" 5 | 6 | "github.com/tedsuo/ifrit" 7 | ) 8 | 9 | type serialStep struct { 10 | steps []ifrit.Runner 11 | } 12 | 13 | func NewSerial(steps []ifrit.Runner) ifrit.Runner { 14 | return &serialStep{ 15 | steps: steps, 16 | } 17 | } 18 | 19 | func (runner *serialStep) Run(signals <-chan os.Signal, ready chan<- struct{}) error { 20 | for i, action := range runner.steps { 21 | p := ifrit.Background(action) 22 | 23 | // wait for the last process to be ready 24 | if i == len(runner.steps)-1 { 25 | go func() { 26 | select { 27 | case <-p.Ready(): 28 | close(ready) 29 | case <-p.Wait(): 30 | } 31 | }() 32 | } 33 | 34 | select { 35 | case substepErr := <-p.Wait(): 36 | if substepErr != nil { 37 | return substepErr 38 | } 39 | case signal := <-signals: 40 | p.Signal(signal) 41 | return <-p.Wait() 42 | } 43 | } 44 | 45 | return nil 46 | } 47 | -------------------------------------------------------------------------------- /depot/steps/serial_step_test.go: -------------------------------------------------------------------------------- 1 | package steps_test 2 | 3 | import ( 4 | "errors" 5 | "os" 6 | 7 | . "github.com/onsi/ginkgo/v2" 8 | . "github.com/onsi/gomega" 9 | "github.com/tedsuo/ifrit" 10 | fake_runner "github.com/tedsuo/ifrit/fake_runner_v2" 11 | 12 | "code.cloudfoundry.org/executor/depot/steps" 13 | ) 14 | 15 | var _ = Describe("SerialStep", func() { 16 | var ( 17 | testRunner1, testRunner2, testRunner3 *fake_runner.TestRunner 18 | sequence ifrit.Runner 19 | p ifrit.Process 20 | ) 21 | BeforeEach(func() { 22 | testRunner1 = fake_runner.NewTestRunner() 23 | testRunner2 = fake_runner.NewTestRunner() 24 | testRunner3 = fake_runner.NewTestRunner() 25 | sequence = steps.NewSerial([]ifrit.Runner{ 26 | testRunner1, 27 | testRunner2, 28 | testRunner3, 29 | }) 30 | p = ifrit.Background(sequence) 31 | }) 32 | AfterEach(func() { 33 | testRunner1.EnsureExit() 34 | testRunner2.EnsureExit() 35 | testRunner3.EnsureExit() 36 | }) 37 | 38 | Describe("Ready", func() { 39 | It("becomes ready when the last step is ready", func() { 40 | Consistently(p.Ready()).ShouldNot(BeClosed()) 41 | testRunner1.TriggerExit(nil) 42 | Consistently(p.Ready()).ShouldNot(BeClosed()) 43 | testRunner2.TriggerExit(nil) 44 | Consistently(p.Ready()).ShouldNot(BeClosed()) 45 | testRunner3.TriggerReady() 46 | Eventually(p.Ready()).Should(BeClosed()) 47 | Consistently(p.Wait()).ShouldNot(Receive()) 48 | }) 49 | }) 50 | 51 | Describe("Run", func() { 52 | It("runs all substeps in order and returns nil", func() { 53 | Eventually(testRunner1.RunCallCount).Should(Equal(1)) 54 | go testRunner1.TriggerExit(nil) 55 | Eventually(testRunner2.RunCallCount).Should(Equal(1)) 56 | go testRunner2.TriggerExit(nil) 57 | Eventually(testRunner3.RunCallCount).Should(Equal(1)) 58 | go testRunner3.TriggerExit(nil) 59 | 60 | Eventually(p.Wait()).Should(Receive(BeNil())) 61 | }) 62 | 63 | Context("when an step fails in the middle", func() { 64 | It("returns the error and does not continue performing", func() { 65 | disaster := errors.New("oh no!") 66 | 67 | Eventually(testRunner1.RunCallCount).Should(Equal(1)) 68 | go testRunner1.TriggerExit(nil) 69 | Eventually(testRunner2.RunCallCount).Should(Equal(1)) 70 | go testRunner2.TriggerExit(disaster) 71 | Consistently(testRunner3.RunCallCount).Should(Equal(0)) 72 | 73 | Eventually(p.Wait()).Should(Receive(Equal(disaster))) 74 | }) 75 | }) 76 | }) 77 | 78 | Describe("Signal", func() { 79 | var ( 80 | signalsChan <-chan os.Signal 81 | ) 82 | 83 | BeforeEach(func() { 84 | go testRunner1.TriggerExit(nil) 85 | Eventually(testRunner1.RunCallCount).Should(Equal(1)) 86 | Eventually(testRunner2.RunCallCount).Should(Equal(1)) 87 | signalsChan = testRunner2.WaitForCall() 88 | p.Signal(os.Interrupt) 89 | }) 90 | 91 | AfterEach(func() { 92 | testRunner1.EnsureExit() 93 | }) 94 | 95 | It("cancels the currently running substep", func() { 96 | Eventually(signalsChan).Should(Receive()) 97 | }) 98 | 99 | It("waits for the substep to exit", func() { 100 | Consistently(p.Wait()).ShouldNot(Receive()) 101 | testRunner2.TriggerExit(errors.New("boooom!")) 102 | Eventually(p.Wait()).Should(Receive(MatchError("boooom!"))) 103 | }) 104 | }) 105 | }) 106 | -------------------------------------------------------------------------------- /depot/steps/steps_suite_test.go: -------------------------------------------------------------------------------- 1 | package steps_test 2 | 3 | import ( 4 | "time" 5 | 6 | multierror "github.com/hashicorp/go-multierror" 7 | . "github.com/onsi/ginkgo/v2" 8 | . "github.com/onsi/gomega" 9 | "github.com/onsi/gomega/gleak" 10 | 11 | "testing" 12 | ) 13 | 14 | var ( 15 | goroutineErrors *multierror.Error 16 | checkGoroutines bool 17 | ) 18 | 19 | func TestSteps(t *testing.T) { 20 | RegisterFailHandler(Fail) 21 | RunSpecs(t, "Steps Suite") 22 | } 23 | 24 | var _ = BeforeEach(func() { 25 | goroutineErrors = &multierror.Error{} 26 | checkGoroutines = true 27 | snapshot := gleak.Goroutines() 28 | DeferCleanup(func() { 29 | if checkGoroutines { 30 | Eventually(gleak.Goroutines).ShouldNot(gleak.HaveLeaked(snapshot)) 31 | } else { 32 | // allow enough time for the goroutines to stabilize. Otherwise, sometimes 33 | // new tests could start while goroutines are being created and the leaked 34 | // goroutine is reported for an unrelated test. This is specially true for 35 | // the monitor_test.go which disables goroutine checks. 36 | time.Sleep(time.Second) 37 | } 38 | if err := goroutineErrors.ErrorOrNil(); err != nil { 39 | Fail(err.Error()) 40 | } 41 | 42 | }) 43 | }) 44 | 45 | type NonDisplayableError struct{} 46 | 47 | func (e NonDisplayableError) Error() string { return "some-non-displaybale-error" } 48 | func (e NonDisplayableError) IsDisplayable() bool { return false } 49 | -------------------------------------------------------------------------------- /depot/steps/throttle_step.go: -------------------------------------------------------------------------------- 1 | package steps 2 | 3 | import ( 4 | "os" 5 | 6 | "code.cloudfoundry.org/workpool" 7 | "github.com/tedsuo/ifrit" 8 | ) 9 | 10 | type throttleStep struct { 11 | substep ifrit.Runner 12 | workPool *workpool.WorkPool 13 | } 14 | 15 | func NewThrottle(substep ifrit.Runner, workPool *workpool.WorkPool) *throttleStep { 16 | return &throttleStep{ 17 | substep: substep, 18 | workPool: workPool, 19 | } 20 | } 21 | 22 | func (step *throttleStep) Run(signals <-chan os.Signal, ready chan<- struct{}) error { 23 | stepResult := make(chan error) 24 | 25 | step.workPool.Submit(func() { 26 | stepResult <- step.substep.Run(signals, ready) 27 | }) 28 | 29 | return <-stepResult 30 | } 31 | -------------------------------------------------------------------------------- /depot/steps/throttle_step_test.go: -------------------------------------------------------------------------------- 1 | package steps_test 2 | 3 | import ( 4 | "errors" 5 | "os" 6 | 7 | "code.cloudfoundry.org/executor/depot/steps" 8 | "code.cloudfoundry.org/workpool" 9 | . "github.com/onsi/ginkgo/v2" 10 | . "github.com/onsi/gomega" 11 | "github.com/tedsuo/ifrit" 12 | fake_runner "github.com/tedsuo/ifrit/fake_runner_v2" 13 | ) 14 | 15 | var _ = Describe("ThrottleStep", func() { 16 | const numConcurrentSteps = 3 17 | 18 | var ( 19 | step ifrit.Runner 20 | workPool *workpool.WorkPool 21 | fakeStep *fake_runner.TestRunner 22 | ) 23 | 24 | BeforeEach(func() { 25 | fakeStep = fake_runner.NewTestRunner() 26 | var err error 27 | workPool, err = workpool.NewWorkPool(numConcurrentSteps) 28 | Expect(err).NotTo(HaveOccurred()) 29 | step = steps.NewThrottle(fakeStep, workPool) 30 | }) 31 | 32 | AfterEach(func() { 33 | fakeStep.EnsureExit() 34 | workPool.Stop() 35 | }) 36 | 37 | Describe("Run", func() { 38 | It("throttles its substep", func() { 39 | for i := 0; i < 5; i++ { 40 | go step.Run(nil, nil) 41 | } 42 | 43 | Eventually(fakeStep.RunCallCount).Should(Equal(numConcurrentSteps)) 44 | Consistently(fakeStep.RunCallCount).Should(Equal(numConcurrentSteps)) 45 | 46 | fakeStep.TriggerExit(nil) 47 | Eventually(fakeStep.RunCallCount).Should(Equal(numConcurrentSteps + 1)) 48 | 49 | fakeStep.TriggerExit(nil) 50 | Eventually(fakeStep.RunCallCount).Should(Equal(5)) 51 | 52 | fakeStep.TriggerExit(nil) 53 | fakeStep.TriggerExit(nil) 54 | fakeStep.TriggerExit(nil) 55 | }) 56 | 57 | It("becomes ready once the substep is ready", func() { 58 | process := ifrit.Background(step) 59 | Consistently(process.Ready()).ShouldNot(BeClosed()) 60 | fakeStep.TriggerReady() 61 | Eventually(process.Ready()).Should(BeClosed()) 62 | }) 63 | 64 | It("exits with the result of the substep", func() { 65 | process := ifrit.Background(step) 66 | Eventually(fakeStep.RunCallCount).Should(Equal(1)) 67 | Consistently(process.Wait()).ShouldNot(Receive()) 68 | fakeStep.TriggerExit(errors.New("substep exited")) 69 | Eventually(process.Wait()).Should(Receive(MatchError("substep exited"))) 70 | }) 71 | }) 72 | 73 | Describe("Signalling", func() { 74 | It("signals the throttled substep", func() { 75 | process := ifrit.Background(step) 76 | Eventually(fakeStep.RunCallCount).Should(Equal(1)) 77 | Consistently(fakeStep.WaitForCall()).ShouldNot(Receive()) 78 | process.Signal(os.Interrupt) 79 | Eventually(fakeStep.WaitForCall()).Should(Receive()) 80 | }) 81 | }) 82 | }) 83 | -------------------------------------------------------------------------------- /depot/steps/timed_step.go: -------------------------------------------------------------------------------- 1 | package steps 2 | 3 | import ( 4 | "os" 5 | "time" 6 | 7 | "code.cloudfoundry.org/clock" 8 | loggingclient "code.cloudfoundry.org/diego-logging-client" 9 | "code.cloudfoundry.org/lager/v3" 10 | "github.com/tedsuo/ifrit" 11 | ) 12 | 13 | type timedStep struct { 14 | step ifrit.Runner 15 | startTime time.Time 16 | clock clock.Clock 17 | logger lager.Logger 18 | metronClient loggingclient.IngressClient 19 | } 20 | 21 | const ( 22 | ContainerSetupSucceededDuration = "ContainerSetupSucceededDuration" 23 | ContainerSetupFailedDuration = "ContainerSetupFailedDuration" 24 | ) 25 | 26 | func NewTimedStep(logger lager.Logger, step ifrit.Runner, metronClient loggingclient.IngressClient, clock clock.Clock, startTime time.Time) ifrit.Runner { 27 | return &timedStep{ 28 | step: step, 29 | startTime: startTime, 30 | metronClient: metronClient, 31 | clock: clock, 32 | logger: logger, 33 | } 34 | } 35 | 36 | func (runner *timedStep) Run(signals <-chan os.Signal, ready chan<- struct{}) error { 37 | var err error 38 | defer func() { 39 | duration := runner.clock.Since(runner.startTime) 40 | if err == nil { 41 | runner.logger.Info("container-setup-succeeded", lager.Data{"duration": duration}) 42 | go runner.metronClient.SendDuration(ContainerSetupSucceededDuration, duration) 43 | } else { 44 | runner.logger.Info("container-setup-failed", lager.Data{"duration": duration}) 45 | go runner.metronClient.SendDuration(ContainerSetupFailedDuration, duration) 46 | } 47 | }() 48 | 49 | if runner.step == nil { 50 | return nil 51 | } 52 | 53 | subStepSignals := make(chan os.Signal, 1) 54 | errCh := make(chan error) 55 | 56 | go func() { 57 | errCh <- runner.step.Run(subStepSignals, ready) 58 | }() 59 | 60 | select { 61 | case s := <-signals: 62 | subStepSignals <- s 63 | return nil 64 | case err = <-errCh: 65 | return err 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /depot/steps/timed_step_test.go: -------------------------------------------------------------------------------- 1 | package steps_test 2 | 3 | import ( 4 | "errors" 5 | "os" 6 | "time" 7 | 8 | "code.cloudfoundry.org/clock/fakeclock" 9 | mfakes "code.cloudfoundry.org/diego-logging-client/testhelpers" 10 | "code.cloudfoundry.org/executor/depot/steps" 11 | "code.cloudfoundry.org/lager/v3/lagertest" 12 | . "github.com/onsi/ginkgo/v2" 13 | . "github.com/onsi/gomega" 14 | "github.com/onsi/gomega/gbytes" 15 | "github.com/tedsuo/ifrit" 16 | fake_runner "github.com/tedsuo/ifrit/fake_runner_v2" 17 | ) 18 | 19 | var _ = Describe("TimedStep", func() { 20 | Describe("Run", func() { 21 | var ( 22 | innerStep *fake_runner.TestRunner 23 | timedStep ifrit.Runner 24 | process ifrit.Process 25 | logger *lagertest.TestLogger 26 | clock *fakeclock.FakeClock 27 | fakeMetronClient *mfakes.FakeIngressClient 28 | ) 29 | 30 | BeforeEach(func() { 31 | logger = lagertest.NewTestLogger("test") 32 | clock = fakeclock.NewFakeClock(time.Now()) 33 | fakeMetronClient = new(mfakes.FakeIngressClient) 34 | }) 35 | 36 | Context("with inner step set to non-nil process", func() { 37 | BeforeEach(func() { 38 | innerStep = fake_runner.NewTestRunner() 39 | }) 40 | 41 | JustBeforeEach(func() { 42 | timedStep = steps.NewTimedStep(logger, innerStep, fakeMetronClient, clock, clock.Now()) 43 | process = ifrit.Background(timedStep) 44 | }) 45 | 46 | AfterEach(func() { 47 | innerStep.EnsureExit() 48 | }) 49 | 50 | Context("when step takes time to be ready", func() { 51 | It("it should close the ready channel when the step is ready", func() { 52 | innerStep.TriggerReady() 53 | Eventually(process.Ready()).Should(BeClosed()) 54 | innerStep.TriggerExit(nil) 55 | }) 56 | }) 57 | 58 | Context("when the step runs for some time", func() { 59 | BeforeEach(func() { 60 | innerStep.RunStub = func(signals <-chan os.Signal, ready chan<- struct{}) error { 61 | clock.Increment(1 * time.Second) 62 | return nil 63 | } 64 | }) 65 | 66 | It("reports the duration of the given step on the duration channel", func() { 67 | Eventually(logger).Should(gbytes.Say("container-setup-succeeded.*duration.*1000000000")) 68 | }) 69 | 70 | It("emits metrics when contanier setup succeeds", func() { 71 | Eventually(fakeMetronClient.SendDurationCallCount).Should(Equal(1)) 72 | name, val, _ := fakeMetronClient.SendDurationArgsForCall(0) 73 | Expect(name).To(Equal(steps.ContainerSetupSucceededDuration)) 74 | Expect(val).To(Equal(1 * time.Second)) 75 | }) 76 | }) 77 | 78 | Context("when the step errors", func() { 79 | BeforeEach(func() { 80 | innerStep.RunStub = func(signals <-chan os.Signal, ready chan<- struct{}) error { 81 | clock.Increment(1 * time.Second) 82 | return errors.New("failed") 83 | } 84 | }) 85 | 86 | It("reports the duration with a failed setup message", func() { 87 | Eventually(logger).Should(gbytes.Say("container-setup-failed.*duration.*1000000000")) 88 | }) 89 | 90 | It("emits metrics when contanier setup fails", func() { 91 | Eventually(fakeMetronClient.SendDurationCallCount).Should(Equal(1)) 92 | name, val, _ := fakeMetronClient.SendDurationArgsForCall(0) 93 | Expect(name).To(Equal(steps.ContainerSetupFailedDuration)) 94 | Expect(val).To(Equal(1 * time.Second)) 95 | }) 96 | }) 97 | }) 98 | 99 | Context("when the inner step is nil", func() { 100 | It("should still log the time for container creation", func() { 101 | startTime := clock.Now().Add(-1 * time.Second) 102 | timedStep = steps.NewTimedStep(logger, nil, fakeMetronClient, clock, startTime) 103 | ifrit.Background(timedStep) 104 | Eventually(logger).Should(gbytes.Say("container-setup-succeeded.*duration.*:1000000000")) 105 | }) 106 | 107 | It("should still emit metrics for container creation", func() { 108 | startTime := clock.Now().Add(-1 * time.Second) 109 | timedStep = steps.NewTimedStep(logger, nil, fakeMetronClient, clock, startTime) 110 | ifrit.Background(timedStep) 111 | Eventually(fakeMetronClient.SendDurationCallCount).Should(Equal(1)) 112 | name, val, _ := fakeMetronClient.SendDurationArgsForCall(0) 113 | Expect(name).To(Equal(steps.ContainerSetupSucceededDuration)) 114 | Expect(val).To(Equal(1 * time.Second)) 115 | }) 116 | }) 117 | }) 118 | }) 119 | -------------------------------------------------------------------------------- /depot/steps/timeout_step.go: -------------------------------------------------------------------------------- 1 | package steps 2 | 3 | import ( 4 | "os" 5 | "time" 6 | 7 | "code.cloudfoundry.org/clock" 8 | "code.cloudfoundry.org/lager/v3" 9 | "github.com/tedsuo/ifrit" 10 | ) 11 | 12 | type timeoutStep struct { 13 | substep ifrit.Runner 14 | timeout time.Duration 15 | logger lager.Logger 16 | clock clock.Clock 17 | } 18 | 19 | func NewTimeout(substep ifrit.Runner, timeout time.Duration, clock clock.Clock, logger lager.Logger) ifrit.Runner { 20 | return &timeoutStep{ 21 | substep: substep, 22 | timeout: timeout, 23 | clock: clock, 24 | logger: logger.Session("timeout-step"), 25 | } 26 | } 27 | 28 | func (step *timeoutStep) Run(signals <-chan os.Signal, ready chan<- struct{}) (err error) { 29 | timer := step.clock.NewTimer(step.timeout) 30 | defer timer.Stop() 31 | 32 | subStepSignals := make(chan os.Signal) 33 | resultCh := make(chan error) 34 | 35 | go func() { 36 | resultCh <- step.substep.Run(subStepSignals, ready) 37 | }() 38 | 39 | for { 40 | select { 41 | case s := <-signals: 42 | subStepSignals <- s 43 | case err := <-resultCh: 44 | return err 45 | case <-timer.C(): 46 | step.logger.Error("timed-out", nil) 47 | subStepSignals <- os.Interrupt 48 | err := <-resultCh 49 | return NewEmittableError(err, "%s", emittableMessage(step.timeout, err)) 50 | } 51 | } 52 | } 53 | 54 | func emittableMessage(timeout time.Duration, substepErr error) string { 55 | message := "exceeded " + timeout.String() + " timeout" 56 | 57 | if emittable, ok := substepErr.(*EmittableError); ok { 58 | message += "; " + emittable.Error() 59 | } 60 | 61 | return message 62 | } 63 | -------------------------------------------------------------------------------- /depot/steps/try_step.go: -------------------------------------------------------------------------------- 1 | package steps 2 | 3 | import ( 4 | "os" 5 | 6 | "code.cloudfoundry.org/lager/v3" 7 | "github.com/tedsuo/ifrit" 8 | ) 9 | 10 | type tryStep struct { 11 | substep ifrit.Runner 12 | logger lager.Logger 13 | } 14 | 15 | func NewTry(substep ifrit.Runner, logger lager.Logger) ifrit.Runner { 16 | logger = logger.Session("try-step") 17 | return &tryStep{ 18 | substep: substep, 19 | logger: logger, 20 | } 21 | } 22 | 23 | func (step *tryStep) Run(signals <-chan os.Signal, ready chan<- struct{}) error { 24 | subStepSignals := make(chan os.Signal, 1) 25 | errCh := make(chan error) 26 | go func() { 27 | errCh <- step.substep.Run(subStepSignals, ready) 28 | }() 29 | 30 | logErr := func(err error) { 31 | if err != nil { 32 | step.logger.Info("failed", lager.Data{ 33 | "error": err.Error(), 34 | }) 35 | } 36 | } 37 | 38 | select { 39 | case s := <-signals: 40 | subStepSignals <- s 41 | logErr(<-errCh) 42 | return nil 43 | case err := <-errCh: 44 | logErr(err) 45 | return nil 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /depot/steps/try_step_test.go: -------------------------------------------------------------------------------- 1 | package steps_test 2 | 3 | import ( 4 | "errors" 5 | "os" 6 | 7 | "code.cloudfoundry.org/lager/v3/lagertest" 8 | . "github.com/onsi/ginkgo/v2" 9 | . "github.com/onsi/gomega" 10 | "github.com/onsi/gomega/gbytes" 11 | "github.com/tedsuo/ifrit" 12 | fake_runner "github.com/tedsuo/ifrit/fake_runner_v2" 13 | 14 | "code.cloudfoundry.org/executor/depot/steps" 15 | ) 16 | 17 | var _ = Describe("TryStep", func() { 18 | var step ifrit.Runner 19 | var subStep *fake_runner.TestRunner 20 | var logger *lagertest.TestLogger 21 | 22 | BeforeEach(func() { 23 | subStep = fake_runner.NewTestRunner() 24 | 25 | logger = lagertest.NewTestLogger("test") 26 | }) 27 | 28 | JustBeforeEach(func() { 29 | step = steps.NewTry(subStep, logger) 30 | }) 31 | 32 | AfterEach(func() { 33 | subStep.EnsureExit() 34 | }) 35 | 36 | It("runs its substep", func() { 37 | ifrit.Background(step) 38 | Eventually(subStep.RunCallCount).Should(Equal(1)) 39 | }) 40 | 41 | Context("when the substep fails", func() { 42 | disaster := errors.New("oh no!") 43 | 44 | BeforeEach(func() { 45 | go subStep.TriggerExit(disaster) 46 | }) 47 | 48 | It("succeeds anyway", func() { 49 | Eventually(ifrit.Invoke(step).Wait()).Should(Receive(BeNil())) 50 | }) 51 | 52 | It("logs the failure", func() { 53 | Eventually(ifrit.Invoke(step).Wait()).Should(Receive(BeNil())) 54 | 55 | Expect(logger).To(gbytes.Say("failed")) 56 | Expect(logger).To(gbytes.Say("oh no!")) 57 | }) 58 | }) 59 | 60 | It("does not become ready", func() { 61 | p := ifrit.Background(step) 62 | Consistently(p.Ready()).ShouldNot(BeClosed()) 63 | }) 64 | 65 | Context("when the substep is ready", func() { 66 | var ( 67 | p ifrit.Process 68 | ) 69 | 70 | JustBeforeEach(func() { 71 | p = ifrit.Background(step) 72 | subStep.TriggerReady() 73 | }) 74 | 75 | It("becomes ready", func() { 76 | Eventually(p.Ready()).Should(BeClosed()) 77 | }) 78 | 79 | It("does not exit", func() { 80 | Consistently(p.Wait()).ShouldNot(Receive()) 81 | }) 82 | }) 83 | 84 | Context("when signalled", func() { 85 | It("passes the message along", func() { 86 | p := ifrit.Background(step) 87 | signals := subStep.WaitForCall() 88 | Consistently(signals).ShouldNot(Receive()) 89 | p.Signal(os.Interrupt) 90 | Eventually(signals).Should(Receive()) 91 | }) 92 | }) 93 | }) 94 | -------------------------------------------------------------------------------- /depot/transformer/faketransformer/package.go: -------------------------------------------------------------------------------- 1 | package faketransformer // import "code.cloudfoundry.org/executor/depot/transformer/faketransformer" 2 | -------------------------------------------------------------------------------- /depot/transformer/package.go: -------------------------------------------------------------------------------- 1 | package transformer // import "code.cloudfoundry.org/executor/depot/transformer" 2 | -------------------------------------------------------------------------------- /depot/transformer/transformer_suite_test.go: -------------------------------------------------------------------------------- 1 | package transformer_test 2 | 3 | import ( 4 | . "github.com/onsi/ginkgo/v2" 5 | . "github.com/onsi/gomega" 6 | 7 | "testing" 8 | ) 9 | 10 | func TestTransformer(t *testing.T) { 11 | RegisterFailHandler(Fail) 12 | RunSpecs(t, "Transformer Suite") 13 | } 14 | -------------------------------------------------------------------------------- /depot/transformer/transformer_unix.go: -------------------------------------------------------------------------------- 1 | //go:build !windows 2 | // +build !windows 3 | 4 | package transformer 5 | 6 | import ( 7 | "fmt" 8 | "strings" 9 | 10 | "code.cloudfoundry.org/bbs/models" 11 | ) 12 | 13 | func envoyRunAction(envoyArgs []string) models.RunAction { 14 | args := []string{ 15 | "-c", 16 | // make sure the entire process group is killed if the shell exits 17 | // otherwise we ended up in the following situtation for short running tasks: 18 | // - assuming envoy proxy is still initializing 19 | // - short running task exits 20 | // - codependent step tries to signal the envoy proxy process 21 | // - the wrapper shell script gets signalled and exit 22 | // - garden's `process.Wait` won't return until both Stdout & Stderr are 23 | // closed which causes the rep to assume envoy is hanging and send it a SigKill 24 | fmt.Sprintf( 25 | "trap 'kill -9 0' TERM; /etc/cf-assets/envoy/envoy %s& pid=$!; wait $pid", 26 | strings.Join(envoyArgs, " "), 27 | ), 28 | } 29 | 30 | return models.RunAction{ 31 | LogSource: "PROXY", 32 | Path: "sh", 33 | Args: args, 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /depot/transformer/transformer_windows.go: -------------------------------------------------------------------------------- 1 | package transformer 2 | 3 | import "code.cloudfoundry.org/bbs/models" 4 | 5 | func envoyRunAction(envoyArgs []string) models.RunAction { 6 | envoyArgs = append(envoyArgs, "--id-creds", 7 | "C:\\etc\\cf-assets\\envoy_config\\sds-id-cert-and-key.yaml", 8 | "--c2c-creds", 9 | "C:\\etc\\cf-assets\\envoy_config\\sds-c2c-cert-and-key.yaml", 10 | "--id-validation", 11 | "C:\\etc\\cf-assets\\envoy_config\\sds-id-validation-context.yaml", 12 | ) 13 | return models.RunAction{ 14 | LogSource: "PROXY", 15 | Path: "/etc/cf-assets/envoy/envoy", 16 | Args: envoyArgs, 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /depot/uploader/fake_uploader/fake_uploader.go: -------------------------------------------------------------------------------- 1 | // This file was generated by counterfeiter 2 | package fake_uploader 3 | 4 | import ( 5 | "net/url" 6 | "sync" 7 | 8 | "code.cloudfoundry.org/executor/depot/uploader" 9 | ) 10 | 11 | type FakeUploader struct { 12 | UploadStub func(fileLocation string, destinationUrl *url.URL, cancel <-chan struct{}) (int64, error) 13 | uploadMutex sync.RWMutex 14 | uploadArgsForCall []struct { 15 | fileLocation string 16 | destinationUrl *url.URL 17 | cancel <-chan struct{} 18 | } 19 | uploadReturns struct { 20 | result1 int64 21 | result2 error 22 | } 23 | } 24 | 25 | func (fake *FakeUploader) Upload(fileLocation string, destinationUrl *url.URL, cancel <-chan struct{}) (int64, error) { 26 | fake.uploadMutex.Lock() 27 | fake.uploadArgsForCall = append(fake.uploadArgsForCall, struct { 28 | fileLocation string 29 | destinationUrl *url.URL 30 | cancel <-chan struct{} 31 | }{fileLocation, destinationUrl, cancel}) 32 | fake.uploadMutex.Unlock() 33 | if fake.UploadStub != nil { 34 | return fake.UploadStub(fileLocation, destinationUrl, cancel) 35 | } else { 36 | return fake.uploadReturns.result1, fake.uploadReturns.result2 37 | } 38 | } 39 | 40 | func (fake *FakeUploader) UploadCallCount() int { 41 | fake.uploadMutex.RLock() 42 | defer fake.uploadMutex.RUnlock() 43 | return len(fake.uploadArgsForCall) 44 | } 45 | 46 | func (fake *FakeUploader) UploadArgsForCall(i int) (string, *url.URL, <-chan struct{}) { 47 | fake.uploadMutex.RLock() 48 | defer fake.uploadMutex.RUnlock() 49 | return fake.uploadArgsForCall[i].fileLocation, fake.uploadArgsForCall[i].destinationUrl, fake.uploadArgsForCall[i].cancel 50 | } 51 | 52 | func (fake *FakeUploader) UploadReturns(result1 int64, result2 error) { 53 | fake.UploadStub = nil 54 | fake.uploadReturns = struct { 55 | result1 int64 56 | result2 error 57 | }{result1, result2} 58 | } 59 | 60 | var _ uploader.Uploader = new(FakeUploader) 61 | -------------------------------------------------------------------------------- /depot/uploader/fake_uploader/package.go: -------------------------------------------------------------------------------- 1 | package fake_uploader // import "code.cloudfoundry.org/executor/depot/uploader/fake_uploader" 2 | -------------------------------------------------------------------------------- /depot/uploader/fixtures/correct/client.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIEMzCCAhugAwIBAgIQU5lnO1CcFfdgrCSta3grjTANBgkqhkiG9w0BAQsFADAU 3 | MRIwEAYDVQQDEwlzZXJ2ZXItY2EwHhcNMjUwMzEyMTkxMjUxWhcNMjYwOTEyMTky 4 | MjUwWjARMQ8wDQYDVQQDEwZjbGllbnQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw 5 | ggEKAoIBAQDXLZgFBbdMbwFS5gUZhRdY5pbqIYkzasW5nqE6I0vRk72IBREUPyX3 6 | 6YZbnSCxweGPJUw+LO2S/8QUmqa3i9hBq9WPsRwxa6H5lzwQS2Ic8RltKoOSN3iT 7 | +CH2gsTUKZn8S48NcDuGtUG2kXdLSK6bxA31FjTCudcdFa+XrB7DezKP7MXvHNen 8 | JimbKlielp8F59dZS94X3wmjJQ1bXAaZm4cxsXZDf/kE0n9U99vCLy6zV9G9Xob7 9 | SD6mT8WpAJk+p2AFA7NjPQK7mT0ixK0YcSmtbWamA/6VWl99NHz3R/nVz8dvTQ1D 10 | s9t+vcesI5IKCui4b6wFu59Y34s92gPnAgMBAAGjgYMwgYAwDgYDVR0PAQH/BAQD 11 | AgO4MB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAdBgNVHQ4EFgQUDl4x 12 | VM0fmQaIkyOiMIWWYqNejX4wHwYDVR0jBBgwFoAUuZS+addEgTh53BzNQGAK5lvm 13 | SowwDwYDVR0RBAgwBocEfwAAATANBgkqhkiG9w0BAQsFAAOCAgEAYESYi3MHqEnY 14 | ywD+aBcua/4e/bk9DAo5U9uUfL4sLLVr09DHISuKkvSxEfL6OGLNxnypmRJwy1n0 15 | QDi9Fn0rUNak5fxTxQLzw+/1YGlYEVtSGxsFojbRKR9UnWCCeQ3I0XmC31Pl6XLV 16 | Mme4n8U3xAHM2kl3+cFkOLeDXNnaKKtwhSaYnf13XCoxBEyqVT7aUFMaLcJ5K48q 17 | 1AqOz6Lu6lYBEZrA5g8mw7U8hEWYJmY5bcw5hdcK724jShGp/eSepSUpdBJiCrYi 18 | iVlwvP2v/0M7QXugfDKVhernsaBED919iLiskR0l8GgPAYEeZ8xAlVNwjejOOLGL 19 | UMJDJsgq0+XjLY03e+fY9UQyFmrtvTlbN/AhXXxuxxHlXqM+3ZYqmfDka1UiXRQd 20 | mcAm5GJeu1Eb9sXOTGgImbMr3VjbJUCFHucHArKhk+Ciy2snlmf4btG6mZOxXw2r 21 | 7o+Ggxp72Qgg8bz1MR3xltVzZGkxK7fFp/luvfDto4nRYWfZOysJPpc3eI9ZRSwp 22 | sQYkdXq55+FaTe6kW+eihfZspSEQSgdM14JEgBUmPZJ3mTCJqC8/VURN65g4ReQg 23 | aal2rNT/JTQe7Dj0Pbfq+dcOKdYPriI8qd2xl6CTQJQViTYboMQ+h/lpbW7ifxt4 24 | F99CBlSAlfKkYGBsr5OHWcp9xpCvjzg= 25 | -----END CERTIFICATE----- 26 | -------------------------------------------------------------------------------- /depot/uploader/fixtures/correct/client.csr: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE REQUEST----- 2 | MIICeDCCAWACAQAwETEPMA0GA1UEAxMGY2xpZW50MIIBIjANBgkqhkiG9w0BAQEF 3 | AAOCAQ8AMIIBCgKCAQEA1y2YBQW3TG8BUuYFGYUXWOaW6iGJM2rFuZ6hOiNL0ZO9 4 | iAURFD8l9+mGW50gscHhjyVMPiztkv/EFJqmt4vYQavVj7EcMWuh+Zc8EEtiHPEZ 5 | bSqDkjd4k/gh9oLE1CmZ/EuPDXA7hrVBtpF3S0ium8QN9RY0wrnXHRWvl6wew3sy 6 | j+zF7xzXpyYpmypYnpafBefXWUveF98JoyUNW1wGmZuHMbF2Q3/5BNJ/VPfbwi8u 7 | s1fRvV6G+0g+pk/FqQCZPqdgBQOzYz0Cu5k9IsStGHEprW1mpgP+lVpffTR890f5 8 | 1c/Hb00NQ7Pbfr3HrCOSCgrouG+sBbufWN+LPdoD5wIDAQABoCIwIAYJKoZIhvcN 9 | AQkOMRMwETAPBgNVHREECDAGhwR/AAABMA0GCSqGSIb3DQEBCwUAA4IBAQBJiAuE 10 | We5lkagPhIJHlbFaWzB7B2jwn2fqE/o26HrvZt+p512bjq0Eg2zq4+o4GcpftkHB 11 | 37fro2em3G4i3yRy4LBd29wwarfFg/fqUEJBGKZ6q+hSbvE0GVEO8+GsgVcE+y3B 12 | DiqxH9XsEz4KpaN+1cUhMJRVYfjEWvXUX7hTA2fTKCKT53woUuwSibTnmO7CS5e4 13 | ih6g4+VlNOaybKMPWKXoQYs2tTICIKgmGITUFOFNaNe2rYpZS40GASLcIbfkDYQQ 14 | sexKbqVrnRNmOD4I6KE82siNblWjoimEVaZDVf2oN5dD84p/nqIg1T7PdZTZ+Xbg 15 | i5XuqIOhcFqDL8j8 16 | -----END CERTIFICATE REQUEST----- 17 | -------------------------------------------------------------------------------- /depot/uploader/fixtures/correct/client.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEpQIBAAKCAQEA1y2YBQW3TG8BUuYFGYUXWOaW6iGJM2rFuZ6hOiNL0ZO9iAUR 3 | FD8l9+mGW50gscHhjyVMPiztkv/EFJqmt4vYQavVj7EcMWuh+Zc8EEtiHPEZbSqD 4 | kjd4k/gh9oLE1CmZ/EuPDXA7hrVBtpF3S0ium8QN9RY0wrnXHRWvl6wew3syj+zF 5 | 7xzXpyYpmypYnpafBefXWUveF98JoyUNW1wGmZuHMbF2Q3/5BNJ/VPfbwi8us1fR 6 | vV6G+0g+pk/FqQCZPqdgBQOzYz0Cu5k9IsStGHEprW1mpgP+lVpffTR890f51c/H 7 | b00NQ7Pbfr3HrCOSCgrouG+sBbufWN+LPdoD5wIDAQABAoIBAQDAKy7l5Vny//v9 8 | rgGF7g+QzLaguHyQl92nzVyN0HHo5HnS3TuIinD9O+hLL0PAnLc1oQi7SmKN8q+J 9 | +yfDKjhjRfP/VRwposdQYVk58CjaUhP0I5DHZ5TfCS5DujvQgqrL4CsMxFvVDVF3 10 | m+gfKvUNlYUlicRq14+eoPxlh0keJ+eqFgH60R4G1YnU6+1CDHzbGAnnNjy31VJZ 11 | JdxH5phO+ZsniSPXJB1hxrw2jYXPflQmtCUjA8B2Dt3D0W7mLQ50uWmF2nlxteNe 12 | veL+gys4MoVB5soIrUrNP87SgMbmeebdOs3VxDqU204J65ia9cjQ25AtBP7HLp3k 13 | 0kP+CXs5AoGBAPYfLuVgqavK5Djve/Mfho3FKMnyWJN3xE74zpQMKwYx5n/a3P2i 14 | HeCHOBLLU0vuPCxDw8fbXG4zpYyU/tKcvcY7zCmbcYTdKTqBKH74BR+MOha8dYRk 15 | Dx7mcP5Ct5LxsC9Ben8Q2AbarIohbAw5X4Xe9sWqCoCHa5Eb+tQ7ofJ9AoGBAN/Q 16 | eYWF8lR9YGALrSCTr9MTTC0e3iy0CB8uD64vvCAstB9pmfkYUYeIBFemqjB/qv/K 17 | HMI4XNKRAipcKngU70aP0sP1mfhotr1804qpnexVOSUtuLh54lkjxDbmn+G4FXuL 18 | /lnkh669S/C+fK+dTf4ZWF++9Kb2pU6Vs0yjcpkzAoGBANftib4x7QnMKigNa4hk 19 | Wy8cD2oFVVKjm7XRMaPPfRulQd1gDcvzpBStbTOH8N9H9sC6/xPjTxdb9lz9BweN 20 | /izhn3/NYW24fohWcknanNwNsZTq6IsrIdzxPabEr7uakQEUiDzccTqqNP/GzL14 21 | xGZ1s7i9MxOKO4QGsSvr2WwdAoGAf5rHviXpTNyStw/RLFKnmytUciE4QLqAKu7D 22 | B+e1VY7HP2Wg4NFJooEdILAoNjCD2QRtsxoZagA9ANO9butYpJ1ZaFo959Aj6BMk 23 | NNmR7W2FgDn6KEttjq8Crt58Z1/h96eQY8YUyb6pbl/cjO+dyPLAXQ5tREg5ZX2a 24 | VWaW7tsCgYEA20jSaNvnNFYvFNNWxeG7RQZ8ET9CNbAW00nwfn8KgNzg4dxroV9y 25 | cBYEkiZtaOJEJiUauM//Q3yFz1JsEF+TVrl+jW5DGmqHe1+W8NtwRFinUiA60q29 26 | Xs/sOtY4N1WM8xxIpSyNretsq/Zj6TrQwwz9ZnmWIw+7cY6iL1WAQb4= 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /depot/uploader/fixtures/correct/server-ca.crl: -------------------------------------------------------------------------------- 1 | -----BEGIN X509 CRL----- 2 | MIICgzBtAgEBMA0GCSqGSIb3DQEBCwUAMBQxEjAQBgNVBAMTCXNlcnZlci1jYRcN 3 | MjUwMzEyMTkyMjUxWhcNMjYwOTEyMTkyMjUxWjAAoCMwITAfBgNVHSMEGDAWgBS5 4 | lL5p10SBOHncHM1AYArmW+ZKjDANBgkqhkiG9w0BAQsFAAOCAgEAkyywdv3u645V 5 | MlBne9fZM6nwjgWuWDxiqaaskf8cd3GbqTZ5Di0YyW6DetPpbMVbSk6BCfSUDcCC 6 | xJ5JK+ZbaImJelB6OoIURTC+qq3f56ljo5BZP13EzKDFaRABJ9jTUuIBtyqioqkm 7 | d8o8BP3xUpFE7Cw2ZAPE+RBFZt3YO08rIz47B1D+nIsGsdLbZbtHq7sFvGyoS6BK 8 | CZiZLnPXsKYCqChv9Yk/Us/bo1JOK13EqZAdWGTZVc3Aid5V/U6+6cWFrm46MmUj 9 | u3wGuKz4fcVzl6veOtBhcpQ71atiuNMoqEiwrgBbYSyU4euO69BAmBv8Vi+PowVQ 10 | /ST6T6OgpQyeBzbGhcfqXmVZ/r10htOqW/T9tmhBj4OKe7f5yOlv0XSgyz1Mlc6O 11 | HjtvKpEnnhu4qCOT8eLY5YR+JgjX/ldtmUu2XWAkAM/KjjipTqJudG6j18FKX6we 12 | nWozuCxur75TClZA8Bi0uJoLJhtygjFmQwNXWrmec7XXNYbi3x3XLH9w2XopxwG8 13 | CLsysqoURQjXfccYQj0Xe196G6QiHq08TGQMFyCX/DrgHVnyqXEGxqVH4q7BnYo2 14 | PZPT6XuawD9tRTU/SUQb1VAbrV6EUQMAoRwaKW1Fee/Yhckq9UW3PEqsXFzw1CP+ 15 | Jnmj64FWhcBJ9U6wM1ZOvAk3pRqbwM0= 16 | -----END X509 CRL----- 17 | -------------------------------------------------------------------------------- /depot/uploader/fixtures/correct/server-ca.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIE6DCCAtCgAwIBAgIBATANBgkqhkiG9w0BAQsFADAUMRIwEAYDVQQDEwlzZXJ2 3 | ZXItY2EwHhcNMjUwMzEyMTkxMjUxWhcNMjYwOTEyMTkyMjUxWjAUMRIwEAYDVQQD 4 | EwlzZXJ2ZXItY2EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDR7vGJ 5 | cm+trSQ82fw/1XRsLSb7ORZLe8IGevpJmUmakhvsJjkREu4Pnzo7LWPVBV/MPDl9 6 | kJqFxae2IgY0btozZcoEgAJ3M36I+jIZvt+YcXqHKr5EpjtDVYmWFbdCG9y09L8U 7 | /fh4A86D5gXJuo3oeo3TYcKUtZQMUwzjHi1MOU1M6flHhIVbfsfB1qpacvEKXOmc 8 | jrlGBT/9tCui7zA/vp6aF8gQH3qlOo1H3dxiJh43hTjGAG92YK12YoWD2daTMG48 9 | PYDHJHY8plfCFj5JDyNmhFV/4Z1yTEl0VtrRz9ndDzOQ2wiPiq99uHGRZhALkfMb 10 | 5wb1w2k5QHxMyWPSd6h2eHaDcFaS5hDEQGAax1TOr2D6s8lTtX3W4+mAoFQ0coU3 11 | lg6V+pbu9iiIQWXlUB2GYn9F2mbXnDIZJplrhC6viTWYRqD/X2rqtTcyJh4dCw8V 12 | 0URVFK2jnnjr9RsXWkPeuzY+g/BPOkS5u+n/g7QV0NDSuk1WRyaw7W/NI1fDLMko 13 | 9FnraEVrgryV3EO9/DW3674pVx5kC6Ut1JAMiMdXS6F/29deihWY4wthx8R4xulr 14 | yVdPJj78vcmxKJUkEPvSOBlbmK/F0/l4spGpnH5DQ4I5ITgKX766639E7WGnmrSa 15 | Wzr8npwrMo9g2jfWbQZOf8pG4IaQ15rYHgUTWQIDAQABo0UwQzAOBgNVHQ8BAf8E 16 | BAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUuZS+addEgTh53BzN 17 | QGAK5lvmSowwDQYJKoZIhvcNAQELBQADggIBAAwV7HQpElr7yhKZAuQI2iSe1XyL 18 | AE1d2uZZ5mFhqgzmxTu8RFCRF6mRxRmLJyvuSv00urEqK1a54Qj7R9WoLPVw01g5 19 | tsoc05qS+7LUl8Zxo/dLLjrv+qIUHaurqbG91ljQ1UqPpSwMUPu46budIrjRkqg8 20 | Eo5UA85dfoco7jk2cMJ/YBOzuLSjPzS2/o7CO6NhuUOw2VvzLi+5lieoRIyvJA/Z 21 | 4Ul8UsfF7Frj5cqE+IjKbjZuMVg4OQePDBr+HEpNa3zk3oDuXtHj3SKW+rGohncK 22 | fcUx/B42WhL8mUOPOv9uGBvHgj6Au1psrB6bro05nzpd2OsiMvHj2mNXKObzX9sr 23 | H0m7srVdqeFNnhf3hbe83+Z8ovRy3GDfkD1FUaR2tsryrQe7XMdM6PEd4zRDWxb2 24 | 1cPCxKYQYd6AmkIvC56fDeeY27IJY8Du/tYMz542ooudbxlOGfRiMkNrhY6ZmEDj 25 | s+wk07TQxhaHwWcOB90yp8hiS//UgSXZ1GNveHvRJx1ykVHptOKeSiZW9RMf+W03 26 | LSV5BK+Y2ZHtoR+3yWqeGTc9XgA+p76Oht8pXR7TS5AWe7gNmd7tdcGE9U2OAriu 27 | 0Hm1bSVAp9bniWpM6hEES0La9/98YjQyMEJIsvc1Pe/Mu65sh4+iovKyeTlrLhxh 28 | w6bvAgMgC0v2p9px 29 | -----END CERTIFICATE----- 30 | -------------------------------------------------------------------------------- /depot/uploader/fixtures/correct/server-ca.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | 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 51 | -----END RSA PRIVATE KEY----- 52 | -------------------------------------------------------------------------------- /depot/uploader/fixtures/correct/server.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIETjCCAjagAwIBAgIQFVzN7QAg6Cxd8uym3F0LUTANBgkqhkiG9w0BAQsFADAU 3 | MRIwEAYDVQQDEwlzZXJ2ZXItY2EwHhcNMjUwMzEyMTkxMjUyWhcNMjYwOTEyMTky 4 | MjUwWjARMQ8wDQYDVQQDEwZzZXJ2ZXIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw 5 | ggEKAoIBAQC8CCiFWo7igYGP7Ed3/m63Wn+H/lXYC2TcTTnyE9YWxfmySoBYBD27 6 | M+Z86J2aKSc06wbnhieLg5HImy2mWUX8R4PaBA4v0O5DQnRA8GjP4WaeULv6uXfg 7 | u/8Sz0lDfOAMfYqUkIVntfNx/9xDIq82hcrlpl3AcKfzXt+4tbMf84n98vXxD9va 8 | L8dr+I2dcypHz+CyCYG6kQWfAq0xh3OE0tgKMWziTqELpTXb/Dn3kBptvR3pnuUl 9 | 9Io5KvaG+Itr3Opx/1zjWfH2HmeOvWCPF4PubJnhnqwVJBL1OGx2NNl18DPwKSPr 10 | KSHvl8WauoNK267d6fTdl1JHS/BsM+BRAgMBAAGjgZ4wgZswDgYDVR0PAQH/BAQD 11 | AgO4MB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAdBgNVHQ4EFgQUUsJS 12 | xqXoR7jgdZyRWX24sCMDie0wHwYDVR0jBBgwFoAUuZS+addEgTh53BzNQGAK5lvm 13 | SowwKgYDVR0RBCMwIYIZKi5iYnMuc2VydmljZS5jZi5pbnRlcm5hbIcEfwAAATAN 14 | BgkqhkiG9w0BAQsFAAOCAgEAfjg0r4PApkUUU2L6PjVXPuX7q8gqs1AwiRSjHLdQ 15 | sqZW956NB07OqecOvdwlDgVp2DorTIpKU7XkezJYVmq/KehZSxRkCLKg+HHdRaLy 16 | e1G6YymrIyS5bfy4EeM+mWFFWkQ7VzpQ0WQjFetC+pm5AVARdpYClff5+V0eFK3h 17 | JrgftF0qhMgUYkOJ4I/l8X3juwgltWsRxGQoiLckmlRxTt1xuFQlIjz/DAzKaTG7 18 | bfCi7rXSr2CQBDoV4yEpLSSHASugPzQu/5awnaD7bdqW41uI+qndbngldfbncERX 19 | 2ws0CpgYWY0lyICWX6moI6Kqb8aXq6pRg+CLTV8P7Uk0B6OOi4n4Y2v4DzUeGiaU 20 | AAGbN23rV6B37AckF8FEgPomy0+jN6t02MpJO2gkdV7DWu2t3UWpDxdJoII5oHka 21 | Y094+YcSJcNJDAIgerJPXYlxYsM8g/l/e/eTnlf3434a1RDYZIcFbt0X7LFw6QC6 22 | 5JBO0bXs6/CDOZJHY7XzRXrsl/Tmv2zfS8/jf7kjbht1MHvXcRDlDGzToUnEEQym 23 | Knhc8QKwLL+zDq/kP0YN40TDVQ+uyMv1uyq4TkGIFo9uRA5rIR4C8yecSlsSIAEZ 24 | r2s83JtyrXexQ9nxwxsopAgNhrd5e77kSBHo0PE/Mdt6gbWJhrWXykRUt94Ns1qT 25 | syk= 26 | -----END CERTIFICATE----- 27 | -------------------------------------------------------------------------------- /depot/uploader/fixtures/correct/server.csr: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE REQUEST----- 2 | MIICkzCCAXsCAQAwETEPMA0GA1UEAxMGc2VydmVyMIIBIjANBgkqhkiG9w0BAQEF 3 | AAOCAQ8AMIIBCgKCAQEAvAgohVqO4oGBj+xHd/5ut1p/h/5V2Atk3E058hPWFsX5 4 | skqAWAQ9uzPmfOidmiknNOsG54Yni4ORyJstpllF/EeD2gQOL9DuQ0J0QPBoz+Fm 5 | nlC7+rl34Lv/Es9JQ3zgDH2KlJCFZ7Xzcf/cQyKvNoXK5aZdwHCn817fuLWzH/OJ 6 | /fL18Q/b2i/Ha/iNnXMqR8/gsgmBupEFnwKtMYdzhNLYCjFs4k6hC6U12/w595Aa 7 | bb0d6Z7lJfSKOSr2hviLa9zqcf9c41nx9h5njr1gjxeD7myZ4Z6sFSQS9ThsdjTZ 8 | dfAz8Ckj6ykh75fFmrqDStuu3en03ZdSR0vwbDPgUQIDAQABoD0wOwYJKoZIhvcN 9 | AQkOMS4wLDAqBgNVHREEIzAhghkqLmJicy5zZXJ2aWNlLmNmLmludGVybmFshwR/ 10 | AAABMA0GCSqGSIb3DQEBCwUAA4IBAQBL/YO9tVIXWWP5ZQziBEnsy7E1rcaaWAEc 11 | IPypis1Xroxlu+MnN5Egw79X/Mt3wt6OLVWI+Wc9OTAMQC4D+oDadM+Khqpl/HX8 12 | d7iaB28bZlrdJJXAQAeb4ibAcEdFre3czT7zi/tS3lLnwd9Jf42+mK4eKF3VZsgJ 13 | pHMdUIRbEMfjnALlyBWX3wEgFLl4kKbzO+Yx5XB+uevAnlAUmj23zTpgGrJAkzgR 14 | tKge63SjPOO+SmfCJZkIMsoXIZsNRPSXK89fgugRL8eoqn0x/Awl2N8LRn3mMgXG 15 | nXj9cnX8AqUCUi58k8kPWa/KZAYHlA6oaJrSmeiEFcxWHPBO04kU 16 | -----END CERTIFICATE REQUEST----- 17 | -------------------------------------------------------------------------------- /depot/uploader/fixtures/correct/server.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEpAIBAAKCAQEAvAgohVqO4oGBj+xHd/5ut1p/h/5V2Atk3E058hPWFsX5skqA 3 | WAQ9uzPmfOidmiknNOsG54Yni4ORyJstpllF/EeD2gQOL9DuQ0J0QPBoz+FmnlC7 4 | +rl34Lv/Es9JQ3zgDH2KlJCFZ7Xzcf/cQyKvNoXK5aZdwHCn817fuLWzH/OJ/fL1 5 | 8Q/b2i/Ha/iNnXMqR8/gsgmBupEFnwKtMYdzhNLYCjFs4k6hC6U12/w595Aabb0d 6 | 6Z7lJfSKOSr2hviLa9zqcf9c41nx9h5njr1gjxeD7myZ4Z6sFSQS9ThsdjTZdfAz 7 | 8Ckj6ykh75fFmrqDStuu3en03ZdSR0vwbDPgUQIDAQABAoIBAQCXeU8DVpeCmud/ 8 | xM0yOjKA3JOeP2JyP4OKAWBrxlUSVXw4h9HqlcgRFddYyp+jwAFInQkb3DPhLSV0 9 | 4KWeu44olIgASoIPPRWj81XptoII7UCYytsUOPL8hRYP1hLkHiXzifLoiaAekzJB 10 | pOeQ4dEacB+qbyJZU6fI46YAi8d4NXny32FFKXHFJrwURWcdQxBEj9mrZY3NWwIS 11 | 79XwUkFxYTLlvhujJMv+h3VJzW+v6oYvqlCBCH3LTiMUnORJX0FmI7utobNIypp6 12 | E+NU/uX74DOV8QcuWgcOrlxz1kvToJuVGhyKmxIAUVTJYM3HlJbqL+AMUg080VSv 13 | FOrKpvvRAoGBAPc04rRisONbpa6L0fdda1WGiiapd1+hx8o1AZKEZm/3+etmvEc9 14 | YjJSRzDvrpvZ/F9lU2qebPYbyysOkQnYWZmtxxVAVhLwhA+MVVq/PDJdXTNpU0DN 15 | PkYvXl8kdQSMA4UZoF5CgNb4LOugtFBwbz50x613HCAJyjlt6wXmZLslAoGBAMK4 16 | al0CG2GvNLJKkrE3eyVmSoLwRstPlH4t8N2eHF/j8OQv5IfBrPqDQXW3ylv0cAb+ 17 | 2S1Ar/pgpJJkUYGMWwk0Y6FQOOt6o/GgO3zsbqrSqdDxia7P2ujTRsBlxImP38io 18 | uRZsPgECCiDLeDU9XjOdJw5LQbasIlCYbwqsW/69AoGBAKHiMxeXjWjF6mC8VVpd 19 | Bd3zBeM9lNu+UNxdC9OL+p0WUcZS97bbPsPfV5l3S+vpuzgpXY/zgT1FhC2FE3vT 20 | /xEBWN7Uy8kJUiHwbzDHDL+anl79eTR1c3N4r580e6Dno6J03qz7de3QhXIkQhBv 21 | IJpQ1TYGSxe78X7cOU0azBo1AoGAGQOdzlLt94+NYnYIADITZMuOOOHrBkUz2z3F 22 | moKsPHlIwdeRMQtlUE06RIgWu9db6NomRhTwRmbR3Wh7u/uu2jDbt6ZZmY6IrwqZ 23 | ecPZt6IWZJwSxt02zwANL7wjElTkN5/NHx9Km9CKQopA5/35MwI2OTTbvT7Brb7X 24 | TPS1YLUCgYAdWGmGuozrn/9RFpyeG9Jwi11xavGv61Ic0VfMGEpgcZ6czKJjagib 25 | ABfsRWcHhx2Jfv0vAshekNnYZKsrQRZryBVSBD5ckAonHbOMw49ZhtH5VtcrJnfc 26 | kvXTxZJbG2VT2ykhrrgGCvaQ5vw31F7VIpW9OANOi/awwF4DNCG8Hw== 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /depot/uploader/fixtures/incorrect/client.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIENDCCAhygAwIBAgIRAMU/ccAkHKkOipulQJhMVx8wDQYJKoZIhvcNAQELBQAw 3 | FDESMBAGA1UEAxMJc2VydmVyLWNhMB4XDTI1MDMxMjE5MTI1M1oXDTI2MDkxMjE5 4 | MjI1MVowETEPMA0GA1UEAxMGY2xpZW50MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A 5 | MIIBCgKCAQEA3uYJHH0NXxv4/DR7b7MJr4y26ltn7oLe/WuwuuYwyCiQiFQeekL7 6 | OTCw1zbPMIdkVkGVUDRSOtsiVKHwH4GeMBlS+crI91nxy8d/xEqvYQ5pnomYij/Q 7 | YR62H/tvrmTV77r035XwofPIHC5VxNvu3YeObY0xCqG9SjEIZ+Yt4UVWy6Tg4BXb 8 | lvH3lMWksdXQNFDwhOc1BA2o4dS52Zuy/gE19/TM4cCLkxMmNVcVqj9vuubT7g6G 9 | wUMjSgQAQimONti8SM66pYPdpGhOrUREZ7z8os84JrCHaVHqUiP+gaezKNZ171CZ 10 | aTsrAoidMQPrPvE3oslVg1UaH6MeZJpGeQIDAQABo4GDMIGAMA4GA1UdDwEB/wQE 11 | AwIDuDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwHQYDVR0OBBYEFAns 12 | p3xtzeK6t/7D01R3iOSNXdyiMB8GA1UdIwQYMBaAFLw9vDQaz74JGOPNXUlrwcBd 13 | JZmhMA8GA1UdEQQIMAaHBH4AAAEwDQYJKoZIhvcNAQELBQADggIBAEsc813t44xu 14 | K5DPG8k9GpZQGRh65SOcEMhBs6LjbfE2zH1/3Hoh7ChO5WG+hYX9kOvT7Hsvq9QL 15 | R6USS6xZS0inCHclxpH6XrB4YgsCbrrofgMQsoS5G1q4NUrIQt8q0m/Nnk384OPw 16 | 2P4dMjWRQVCeOfx8Z64I5/2ZeCqUMUfm95ROHU1CPJ2teEY8nNZIXi4acZX5mxHD 17 | AON0sb5iTmOV49BUhm25/99FnKZTj/0jhnintmCZuUz6xgZbianrNWhWIrDhXmjC 18 | vXavFZw4Pu8MOhpGpAfRcR+gqfwS5CTdKPn/6IW7LoAkv3e1ycK3rVOfrUyb1Dho 19 | 5DsH150s2cNQeBnIJSGnW3sbBnvJ9Sv8OTbJcPAh6bF11Q8o710pcMBEEkEmL7uV 20 | GWnck4c1DS4AIiOi8qTvhfggC6DkVVybZGcN15mmp7x+DhDw3TFPrE8ok17mRpkN 21 | vMlsU6ZQaaR5LSAtCblJ8IEtPX8qZaAd9q9pIMcS7W3Wa1Vn4DLlBBSP2LPFYx55 22 | tNtfIuXPSPJBWru2xNKeQrbfx0LnjNwe8cv/kEEwE+xOh1H36SUzt7E0sXvHPJiN 23 | R1xA2mtQcUGle+obdMwSr2dO6kwJ7iTyuj5JXLWj89icAl/TzqaBoinOT4kuz//j 24 | clInhvTZI3D1IrnU4igkLIUq4a3rtIZx 25 | -----END CERTIFICATE----- 26 | -------------------------------------------------------------------------------- /depot/uploader/fixtures/incorrect/client.csr: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE REQUEST----- 2 | MIICeDCCAWACAQAwETEPMA0GA1UEAxMGY2xpZW50MIIBIjANBgkqhkiG9w0BAQEF 3 | AAOCAQ8AMIIBCgKCAQEA3uYJHH0NXxv4/DR7b7MJr4y26ltn7oLe/WuwuuYwyCiQ 4 | iFQeekL7OTCw1zbPMIdkVkGVUDRSOtsiVKHwH4GeMBlS+crI91nxy8d/xEqvYQ5p 5 | nomYij/QYR62H/tvrmTV77r035XwofPIHC5VxNvu3YeObY0xCqG9SjEIZ+Yt4UVW 6 | y6Tg4BXblvH3lMWksdXQNFDwhOc1BA2o4dS52Zuy/gE19/TM4cCLkxMmNVcVqj9v 7 | uubT7g6GwUMjSgQAQimONti8SM66pYPdpGhOrUREZ7z8os84JrCHaVHqUiP+gaez 8 | KNZ171CZaTsrAoidMQPrPvE3oslVg1UaH6MeZJpGeQIDAQABoCIwIAYJKoZIhvcN 9 | AQkOMRMwETAPBgNVHREECDAGhwR+AAABMA0GCSqGSIb3DQEBCwUAA4IBAQBFS47X 10 | lsRJY1aruX1bDGoU9WEBa+0+6/4ltKMHLySokq6w0Ba6EiBv2Jv0EXEsWQ5TGifJ 11 | Pi1WhuB0bBDN7JL61F0ly4uwpMJjx1xZ2/oRqyUxUhEwLDY06CyUAlinGnSGByjX 12 | 2uYSeY78q1H4soZk63X/PgR5GOYd8r8KFOVVEmBv09twc1RuvFSB2GR1/u0bcXUJ 13 | Ui+R55xYS73vVRPDWlmDhi2dMwSVDuSG9/YK97ywlrhGaPDssharSMzO/k08EqGb 14 | CChc6TIRMREVUjT2MdWsshSPm6HJfeBCrJjU6HnOLc0CQPQ5XBKqDvUDcKKowaOi 15 | s0hRZkQ5+oOy+fVZ 16 | -----END CERTIFICATE REQUEST----- 17 | -------------------------------------------------------------------------------- /depot/uploader/fixtures/incorrect/client.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEpQIBAAKCAQEA3uYJHH0NXxv4/DR7b7MJr4y26ltn7oLe/WuwuuYwyCiQiFQe 3 | ekL7OTCw1zbPMIdkVkGVUDRSOtsiVKHwH4GeMBlS+crI91nxy8d/xEqvYQ5pnomY 4 | ij/QYR62H/tvrmTV77r035XwofPIHC5VxNvu3YeObY0xCqG9SjEIZ+Yt4UVWy6Tg 5 | 4BXblvH3lMWksdXQNFDwhOc1BA2o4dS52Zuy/gE19/TM4cCLkxMmNVcVqj9vuubT 6 | 7g6GwUMjSgQAQimONti8SM66pYPdpGhOrUREZ7z8os84JrCHaVHqUiP+gaezKNZ1 7 | 71CZaTsrAoidMQPrPvE3oslVg1UaH6MeZJpGeQIDAQABAoIBAGnq2Y2GBuKZAjmm 8 | Hrm3U/TtYsX+ZWa7HYdCsxo85BVY4UVG46ypQ4OrlXzO+KlQzOcIBxGzqxd4pdmd 9 | keMGzsqAXiOArvqK7REuXZJDAw+Vr668J5YaOMTNuTF9Y1Z1aAugxVexgkUS+JYb 10 | lnoTIHB4R7/bBeDNdotYvWvRvx951nzDYU/Gk5dyBGNwiYqveGB++jGxZn64dkqw 11 | vjBWbXICE2fvdUOF7FAu1VoOIjuTgaDTlupl0S/ie7mjJ1+DY0ZcjWqpBY2CZWFm 12 | veZxuijT+PGmG30yt2mIcX7ImaqWivRVsDoA3Kd2BeSIDxaXNxTVtrq0osdH+DR8 13 | nRaZXQECgYEA7tWQ02g8fgEHUlRSHeoEcOk8Ml+88M3l8HcNZRfIdyotJjkhQVLV 14 | n97cbBkQZjRWTA2kYZCFf9dlGyIkaFy36sDL3UTvrCn/t3YTFQdN/no3X+oqQh4i 15 | E+YTq9mSER8QsB2R1CZENHVVLdioLHYkgYmJl+tvlNxCC9PHCdg5tPECgYEA7utC 16 | 6IhXE8hYAt7JArv43uxz9lnP21nbU/h9cFYATL3Ra1qDiMWOo8ZF1wXF2k7IoD8D 17 | i9lHf0/m2OuYGbDowyDSjrEWk1HnqHnk12vMJZWLx4UTy7Q61ASqnQuAN4HK9/jd 18 | k4if1Iiup4kFJ+RNE21BhIUHzJ9KsiAWZjuZigkCgYEAoBe0HqGueuABomQ3Lyog 19 | k/cjjLi0E85QpaGH7w3EKGyzGv4MlpcJ70IaCrO6VGgcuJokZ+nSMuGVOlzmfrY3 20 | 6joV7Vo6NfNpH/cbz2q4Ey6lU7vJW8yLFz+QTA9pY+So8QTBLa4A5hEIadTi1frT 21 | ealR++2rO+NwujDZKHYyKGECgYEAoFxgKFt6tth92k9Wc/Ne86GZo/xcO0pwoEfl 22 | SgUvZlLxwTCboK2ZM+vc7Jn/VqwSlRw2cSOBjb4/n9Fh4byQPohFS2kpUfBjoP1P 23 | 0BeWipN5oo173/o0kiIfshEKGjeP2Ci98Ex/mtOzBtg9Ea123lcy5pOzzHAOXsiS 24 | wEO4pqECgYEAtQm1vu+GlvtEfvLhIi6F20ymkYD1FcfgskTgp91O08YOTInopA6g 25 | OAIUTE9VK72o9RHV0uk56++p06aL5zPtBcI/pW0B0/wSFU+27HBi0kpb9os7FiRj 26 | PUDNpCB1LikFGRB50TuWMNJpOYqV/LblJ58u9QicDH+FSJkqoqdSECw= 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /depot/uploader/fixtures/incorrect/server-ca.crl: -------------------------------------------------------------------------------- 1 | -----BEGIN X509 CRL----- 2 | MIICgzBtAgEBMA0GCSqGSIb3DQEBCwUAMBQxEjAQBgNVBAMTCXNlcnZlci1jYRcN 3 | MjUwMzEyMTkyMjUzWhcNMjYwOTEyMTkyMjUyWjAAoCMwITAfBgNVHSMEGDAWgBS8 4 | Pbw0Gs++CRjjzV1Ja8HAXSWZoTANBgkqhkiG9w0BAQsFAAOCAgEACAFLZjVnXTcN 5 | m8E6uV+xSXBqaCjRYsfCQPk4yMqF1mmSkt+hsvIKHSUJ6tZe0IPw5IAObPUVezjQ 6 | CByKN/wKd8O/Eyh9DJbAj2lxNqefHVO4M1EzXa9iCmWS6SXaLZ4VIp5AsOhFea1/ 7 | hQqBZBRIYYUB+TQWSfhqWBLYHQ07jenO/ww+LIxBEzpQ40bX2jNAFsUcAwKC8vT3 8 | Tfv+tpvloESyHIaiST7ey2baazvJeFaV20gxbG6Wbbsfe+qsMPTAnmm3jrOlhqzy 9 | DaE7lVNtfH5izmeFMEFg2ZkZl+vMHOlZv8Qi3Xl8Sdi26ZQsGmtvF6xBkNdz9nbE 10 | KQMBjBMbMENx5q6KsyVsEbi9XGDQFoWwCzbJi/gO2rXCrTVnCXB5dDuoh0nfCbcQ 11 | n/ib7g09Y08u0pPj+qQ+Am7c06teV9v72YxT78b+etX2dAFPIPxExt2fxGtk5J8C 12 | /f7TzBnnUIBD3RT9IpHw+SqzKVZmW/oh58NhBe/BYXIJ1g8W/YXUxaux/XRxKvrz 13 | OJKi9o0tvM3KdjGTDq/OYLsOkPcDer58TcKBOj2gfnIgCKjwWXlfN9mrErkfuZyE 14 | MXZ8Jj0GSDfewNuGLE9/67O/ennrvzOSEhvDKWkC/TwgPdDZZp8MOGn+6BYch/S8 15 | h6ZS8KISXVxB50kmxCsmAVa9DnMMjRU= 16 | -----END X509 CRL----- 17 | -------------------------------------------------------------------------------- /depot/uploader/fixtures/incorrect/server-ca.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIE6DCCAtCgAwIBAgIBATANBgkqhkiG9w0BAQsFADAUMRIwEAYDVQQDEwlzZXJ2 3 | ZXItY2EwHhcNMjUwMzEyMTkxMjUzWhcNMjYwOTEyMTkyMjUyWjAUMRIwEAYDVQQD 4 | EwlzZXJ2ZXItY2EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCvrmDy 5 | AVP6ePuaQUO+BOw1uFgxMg2l16KzRlocGntKXT3nCC3lnr7TM19EJx9S6FNUqjvk 6 | 10FMm2z1HGdxHGjOibM26D9+tcKnXY1ViJkU+TknhuW62mcU2AvV26K0dA3TW+XM 7 | tf+QJboI+aeNeqS0V4ugPvIfUP1NkZMc5Ah3aiq7WUT7xSx3swxnlhTZXjkANHXp 8 | SDibCeWH3s8IOHRFLLNL0m5fKMBGjlJXu0ffTqk087zytH1lBzFXq1YMUndeqMhp 9 | 4N3LyUStxpj3eP+arh5rZQ/+vuoE0uBrFHYQSpcoQ5CT7HhyVDlhXMz9GB8LMEV7 10 | 6FHEraKf/yXAOhQMHTI01tbSthvd2xKIGwh7e5zVpkxUoOcZoqNzooRjcGBCADHI 11 | 5ZilT6GAeOXs+03AkON2YgmJP0A1AziCXyZ2wjrT86JPUVn3uuHv/yMlu8Q4MTdC 12 | J8X+ZL7NqWzLoFtOxIj/vmi/i2EQrhRcDmGh0744HdoXpw79txfa8BgDBIk0/28F 13 | 0xQfJkw4I+3i+vLvgng8wkhuwZXyUiiKSDyVz//mTZTLF5BwyrPur4wyGYUUjJ31 14 | b/NFKh6EcAQM8ZavZfLT11XcEJSBS/uQJfqMKSg6DTDL26bEdpu+N3Y0uB/5iXrD 15 | /+C+JrPpprIsNEo3sy96DhN7n6yuk0hGz85XgwIDAQABo0UwQzAOBgNVHQ8BAf8E 16 | BAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUvD28NBrPvgkY481d 17 | SWvBwF0lmaEwDQYJKoZIhvcNAQELBQADggIBAKPx9ltvLaFsWhoy62PHD/AyKqwx 18 | KN5wJZaBiMWsiLISKacyNj+s8du4ZvWsEEYd4QOOzMa1p+R6hdJrvL1AVBDCxJdD 19 | KNCK5T6fTKxESGl4LNWg8uYKghjtIaddgyPh8nIlBKHzS4ZBY2KvDJXCFExHvEWH 20 | kRpSSAMnfBXununwAeYlIPsrVUUOWCdbYJKOc/b9JecCGKijlFrE4/7GVV8wf421 21 | msPP7gynFrYITYtC61Ytp7/acPH2g683Al+SynemLQLybT0x7x+jgJfPYECMWx3q 22 | trEdRveUCtVuzu/ehsVn+mzHInTC8WlanIa3ZHJ+d1vCdefX84pRBBRxafxf3TeS 23 | OzwqLPZiYRzcwGSL5HqmnyiPx49wnL8qYBd4rJA65FHUEKjJ5XYZ13V2Iww5N3Vz 24 | TAGTs7cgOc1hxC59kd93lD98Pgouf+sh13TUwZ7xbb00jPhR9tFnhK+VQHRxgJC4 25 | /KbaaOVyEb/R8IwEG0RmkBRguyuwl/1MopXsaZinOz5+3KRt8UQ/jeIz13Vkj3Eg 26 | Z1qTVQokrFmGoIu9mSfYSHVLb3JR3r8yY/kE7VOtVEsaOPRMY9qKA6zcBdo0M9E/ 27 | ZyKoevQioDFCltMHz+4Cuy6dkI+A9g+d6XLP8PcpSUQWkreUKdnLPHWl24NMP1lf 28 | Y0feP8WrvMaQ83GF 29 | -----END CERTIFICATE----- 30 | -------------------------------------------------------------------------------- /depot/uploader/fixtures/incorrect/server-ca.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIJKQIBAAKCAgEAr65g8gFT+nj7mkFDvgTsNbhYMTINpdeis0ZaHBp7Sl095wgt 3 | 5Z6+0zNfRCcfUuhTVKo75NdBTJts9RxncRxozomzNug/frXCp12NVYiZFPk5J4bl 4 | utpnFNgL1duitHQN01vlzLX/kCW6CPmnjXqktFeLoD7yH1D9TZGTHOQId2oqu1lE 5 | +8Usd7MMZ5YU2V45ADR16Ug4mwnlh97PCDh0RSyzS9JuXyjARo5SV7tH306pNPO8 6 | 8rR9ZQcxV6tWDFJ3XqjIaeDdy8lErcaY93j/mq4ea2UP/r7qBNLgaxR2EEqXKEOQ 7 | k+x4clQ5YVzM/RgfCzBFe+hRxK2in/8lwDoUDB0yNNbW0rYb3dsSiBsIe3uc1aZM 8 | VKDnGaKjc6KEY3BgQgAxyOWYpU+hgHjl7PtNwJDjdmIJiT9ANQM4gl8mdsI60/Oi 9 | T1FZ97rh7/8jJbvEODE3QifF/mS+zalsy6BbTsSI/75ov4thEK4UXA5hodO+OB3a 10 | F6cO/bcX2vAYAwSJNP9vBdMUHyZMOCPt4vry74J4PMJIbsGV8lIoikg8lc//5k2U 11 | yxeQcMqz7q+MMhmFFIyd9W/zRSoehHAEDPGWr2Xy09dV3BCUgUv7kCX6jCkoOg0w 12 | y9umxHabvjd2NLgf+Yl6w//gviaz6aayLDRKN7Mveg4Te5+srpNIRs/OV4MCAwEA 13 | AQKCAgAQlRsdfLaai9Tj6IkmZHyPTYk1i43yO3pmBZv3zyAYEtkG96StaeCFOvIh 14 | ErhIMRm8gh0JKrBFNN6B/F5fNNlHtYOvCRkFMs7e0VvH2Q7qBeQ5MOh6TKcyNnpX 15 | g1XGRrYPXzs/qWYoCweWVUpVdmAZjbHmPErKXfCq47TJI1URQHosGO8D/MaHveTL 16 | 2kS5h8VFma4PiPue1r5NpuBP3FRNOzzpSUGVxdjwT/rBwTG1iE08bE1Hc3XqlVU4 17 | +zkyDI6r5q6UH9+Pnr3W0UobAdbOmOTSKkXqO8cHEYiRUusZ+pBuAoKhE88Cq6SG 18 | 5iWLNj2n5rSIT5N4RxN0mrbLgC/oFLusN3FNblay88xNJEUffskJUk5SMGkXtcjH 19 | p6t2pnHZKefwEzO2nuoZomC87YW6beF5ByJmiIfhCnCfrgyXfRkP48l+HYxkKJXs 20 | GM/bAw+EAgMtbC0KW3wS5TBCW7QMzpJrQLh3TjXTT4ZDz9W3kT8IE94NqW2NaUWC 21 | 5ugb3ZOXylCTFcd2zri3UI2LUnadunbzo2NyG1EMpt3DOWsUefM++l6qShN8ufSU 22 | o9+MGYsg77+gTS9+05eM/N1FC8mI2zOw5PVftL9ZaQginL/6cqnGlRvDbhDjUQgm 23 | HbcTz2ieBSb4msA4jkrmUrEjdUD0DuYc+P/T3JBmkz7suunawQKCAQEA3uc7FUMW 24 | 4K1l8o542axSmVXvKLHMbt8990VA11/WVjTIPv7YnTEuPHIrtGE/kWulI78s+1iD 25 | s+ELJO1e155ITaDa+2/79857ZissdY4Y7S/H91UPT/VdbyK9BkMpMyZBZH2W7XUL 26 | nI3tDMdKPg8zI4pgOv1fg1ZaDTivdPkNzz0G7k58gOz0FB9W+t1VzqIeOQlzU72t 27 | sKrKLUs7ANQxv4XjWaLfWUWDWNhctxos6eZ6YoxnT55ypWvU3iKQbVJu+UJxGxp5 28 | al2wqYu7DWdImgDjkw/vkdLKxG9oB6bgOtO9gXEMLGc8OovvLoRUuMk6GV3w91/v 29 | HvIXxc3HFOKlcQKCAQEAycQw1Uuwl5lJ3nL4eHjjxtvgpDAnvbBzWJSEYjrimtpL 30 | /pEg/Fl8GQgTnBzABoj372wCMihi3h9I5JkEoRiMFBJbwkH5Ad+BwM4TdeKxefg2 31 | OcBz7NGZkkVPExluSNr65GwBpAVUzhW0QHsIdPdUfm83MnqoxChCC+nBxP2SENHK 32 | /3uF1H044q+7x5yZbCHMMXwbsEweujaPMW2R26HAzdw323XoZuY/vR8/2KennRH1 33 | 1Z9Ves3+VxPUtx2UT1qnsB81Gn476LcuT8VYk7V653UWdg713uEUBPZ9gch635uh 34 | 2FKldpNG41KUBSeLkYDFUzXwFpXh5xn5D/YnluSCMwKCAQEAiXqqmTmQ0bCA8XJo 35 | HTFInKRA5qOKyFNOX8VJ8cx9YRwa6ae7KHCd6NAuHongcCupZfvSnY+BY5+IhRUW 36 | avyH8cElbvEpwjSLLX+xYyvqOdg/iE/hKtrV7ubJGSSxM4gDyxwey4RmTf/HVhtQ 37 | sigjzWbaZWfC0jmfPwpYRVga6Vflf3PPHKGJBSQzPHTpKJIa++jVRa/2gcFFA1yk 38 | HqXBrTPB/pYTFXdnRJPl01UEoJrznvaj/ZpncZmpZ/x/gb3XDkupgSL6Ad2ZSWkS 39 | THkIcVvdAOZSR2lwgGmKCzYklIPmHQEBlh1yK1YFhnY93t7Vw7GKHrj/veFpQini 40 | AQKtMQKCAQBY7iZv/PqK9z990sL9ppsOzV9IPwllLF7KzjtDaJz0j/8q5yDY2UA/ 41 | cDXkey+QMdLGLp8RKIfbS4K/b0qBDua++hCDoLx2PONd7fbZ4N9E2UhdUBxIZ2H+ 42 | /JmL24umhQ5Mm+ZlOwxUAXD/crsZguI1ECQOFc5JF011HsUPZIx66V1GGlW0gLUQ 43 | BVEI/FcLOCJeNUum+wYYIXAf4yGE4tiuY8Ai9OdIY3f4jcuAXPUd4Aqw65erlxvh 44 | mZYKV/lEuLpsgHTRho41VngNJPiTskvHtO3/fzyTzjUasuJCz/CImnpNdLAFgYif 45 | LYicdP+pVE6lDIMUEWAOkn4asO5mLbXNAoIBAQCNzyZpBt5XGHUSnBDsv5yqyO5D 46 | 2d/Cr8eMvsKGPL4pWpYZNb3GJdc7do3WLoRkOTetjbO2aoiEOPGAjfu+/ICl/bOa 47 | 93tvVIuWDLm3uqCRL6ZAn1VWUxig6TnnmuBXgrCRKq1L0SPrTtimAhmhDmCAXTZi 48 | wwUIx9xDt+VXvUvqiXcM78R4b8xadQD+7mx+Lsymj/+NdzGtzq6eZmcBxrdFHa2+ 49 | UDd85LV1nfIy/kq5SANwivE0bnggUmZQMXUCv51n1UGagnLhpgbNS2wvIF1d97Bc 50 | zqgCf3oj60ACjF4gnsvOjQdVgQgVurTSyi39BBlLbESzI4YOQCGUH20ivEn5 51 | -----END RSA PRIVATE KEY----- 52 | -------------------------------------------------------------------------------- /depot/uploader/fixtures/regenerate-certs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | this_dir="$(cd $(dirname $0) && pwd)" 6 | 7 | pushd "$this_dir" 8 | 9 | rm -rf out 10 | certstrap init --common-name "server-ca" --passphrase "" 11 | certstrap request-cert --common-name "client" --passphrase "" --ip "127.0.0.1" 12 | certstrap sign client --CA "server-ca" 13 | 14 | certstrap request-cert --common-name "server" --passphrase "" --ip "127.0.0.1" --domain "*.bbs.service.cf.internal" 15 | certstrap sign server --CA "server-ca" 16 | 17 | mv -f out/* ./correct/ 18 | rm -rf out 19 | 20 | certstrap init --common-name "server-ca" --passphrase "" 21 | certstrap request-cert --common-name "client" --passphrase "" --ip "126.0.0.1" 22 | certstrap sign client --CA "server-ca" 23 | 24 | mv -f out/* ./incorrect/ 25 | rm -rf out 26 | 27 | popd 28 | -------------------------------------------------------------------------------- /depot/uploader/package.go: -------------------------------------------------------------------------------- 1 | package uploader // import "code.cloudfoundry.org/executor/depot/uploader" 2 | -------------------------------------------------------------------------------- /depot/uploader/uploader_suite_test.go: -------------------------------------------------------------------------------- 1 | package uploader_test 2 | 3 | import ( 4 | . "github.com/onsi/ginkgo/v2" 5 | . "github.com/onsi/gomega" 6 | 7 | "testing" 8 | ) 9 | 10 | func TestUploader(t *testing.T) { 11 | RegisterFailHandler(Fail) 12 | RunSpecs(t, "Uploader Suite") 13 | } 14 | -------------------------------------------------------------------------------- /errors.go: -------------------------------------------------------------------------------- 1 | package executor 2 | 3 | type Error interface { 4 | error 5 | 6 | Name() string 7 | } 8 | 9 | type execError struct { 10 | name string 11 | message string 12 | } 13 | 14 | func (err execError) Name() string { 15 | return err.name 16 | } 17 | 18 | func (err execError) Error() string { 19 | return err.message 20 | } 21 | 22 | var Errors = map[string]Error{} 23 | 24 | func registerError(name, message string) Error { 25 | err := execError{name, message} 26 | Errors[name] = err 27 | return err 28 | } 29 | 30 | var ( 31 | ErrContainerGuidNotAvailable = registerError("ContainerGuidNotAvailable", "container guid not available") 32 | ErrContainerNotCompleted = registerError("ContainerNotCompleted", "container must be stopped before it can be deleted") 33 | ErrInsufficientResourcesAvailable = registerError("InsufficientResourcesAvailable", "insufficient resources available") 34 | ErrContainerNotFound = registerError("ContainerNotFound", "container not found") 35 | ErrStepsInvalid = registerError("StepsInvalid", "steps invalid") 36 | ErrLimitsInvalid = registerError("LimitsInvalid", "container limits invalid") 37 | ErrGuidNotSpecified = registerError("GuidNotSpecified", "container guid not specified") 38 | ErrInvalidTransition = registerError("InvalidStateTransition", "container cannot transition to given state") 39 | ErrFailureToCheckSpace = registerError("ErrFailureToCheckSpace", "failed to check available space") 40 | ErrInvalidSecurityGroup = registerError("ErrInvalidSecurityGroup", "security group has invalid values") 41 | ErrNoProcessToStop = registerError("ErrNoProcessToStop", "failed to find a process to stop") 42 | ) 43 | -------------------------------------------------------------------------------- /executor_suite_test.go: -------------------------------------------------------------------------------- 1 | package executor_test 2 | 3 | import ( 4 | . "github.com/onsi/ginkgo/v2" 5 | . "github.com/onsi/gomega" 6 | 7 | "testing" 8 | ) 9 | 10 | func TestExecutor(t *testing.T) { 11 | RegisterFailHandler(Fail) 12 | RunSpecs(t, "Executor Suite") 13 | } 14 | -------------------------------------------------------------------------------- /fakes/fake_garden_client.go: -------------------------------------------------------------------------------- 1 | package fakes 2 | 3 | import ( 4 | "code.cloudfoundry.org/garden" 5 | "code.cloudfoundry.org/garden/client" 6 | "code.cloudfoundry.org/garden/client/connection/connectionfakes" 7 | ) 8 | 9 | type FakeGardenClient struct { 10 | garden.Client 11 | 12 | Connection *connectionfakes.FakeConnection 13 | } 14 | 15 | func NewGardenClient() *FakeGardenClient { 16 | connection := new(connectionfakes.FakeConnection) 17 | 18 | return &FakeGardenClient{ 19 | Connection: connection, 20 | 21 | Client: client.New(connection), 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /fakes/package.go: -------------------------------------------------------------------------------- 1 | package fakes // import "code.cloudfoundry.org/executor/fakes" 2 | -------------------------------------------------------------------------------- /gardenhealth/README.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package gardenhealth contains logic to periodically verify that basic 3 | garden container functionality is working. 4 | 5 | gardenhealth.Checker is responsible for executing the healthcheck operation. gardenhealth.Runner 6 | manages the running of the checker and is responsible for communicating health to the executor. 7 | 8 | For more details, see the Runner and Checker documentation in this package. 9 | */ 10 | package gardenhealth 11 | -------------------------------------------------------------------------------- /gardenhealth/fakegardenhealth/package.go: -------------------------------------------------------------------------------- 1 | package fakegardenhealth // import "code.cloudfoundry.org/executor/gardenhealth/fakegardenhealth" 2 | -------------------------------------------------------------------------------- /gardenhealth/gardenhealth_suite_test.go: -------------------------------------------------------------------------------- 1 | package gardenhealth_test 2 | 3 | import ( 4 | . "github.com/onsi/ginkgo/v2" 5 | . "github.com/onsi/gomega" 6 | 7 | "testing" 8 | ) 9 | 10 | func TestHealthState(t *testing.T) { 11 | RegisterFailHandler(Fail) 12 | RunSpecs(t, "HealthState Suite") 13 | } 14 | -------------------------------------------------------------------------------- /gardenhealth/package.go: -------------------------------------------------------------------------------- 1 | package gardenhealth // import "code.cloudfoundry.org/executor/gardenhealth" 2 | -------------------------------------------------------------------------------- /guidgen/fakeguidgen/fake_generator.go: -------------------------------------------------------------------------------- 1 | // Code generated by counterfeiter. DO NOT EDIT. 2 | package fakeguidgen 3 | 4 | import ( 5 | "sync" 6 | 7 | "code.cloudfoundry.org/executor/guidgen" 8 | lager "code.cloudfoundry.org/lager/v3" 9 | ) 10 | 11 | type FakeGenerator struct { 12 | GuidStub func(lager.Logger) string 13 | guidMutex sync.RWMutex 14 | guidArgsForCall []struct { 15 | arg1 lager.Logger 16 | } 17 | guidReturns struct { 18 | result1 string 19 | } 20 | guidReturnsOnCall map[int]struct { 21 | result1 string 22 | } 23 | invocations map[string][][]interface{} 24 | invocationsMutex sync.RWMutex 25 | } 26 | 27 | func (fake *FakeGenerator) Guid(arg1 lager.Logger) string { 28 | fake.guidMutex.Lock() 29 | ret, specificReturn := fake.guidReturnsOnCall[len(fake.guidArgsForCall)] 30 | fake.guidArgsForCall = append(fake.guidArgsForCall, struct { 31 | arg1 lager.Logger 32 | }{arg1}) 33 | stub := fake.GuidStub 34 | fakeReturns := fake.guidReturns 35 | fake.recordInvocation("Guid", []interface{}{arg1}) 36 | fake.guidMutex.Unlock() 37 | if stub != nil { 38 | return stub(arg1) 39 | } 40 | if specificReturn { 41 | return ret.result1 42 | } 43 | return fakeReturns.result1 44 | } 45 | 46 | func (fake *FakeGenerator) GuidCallCount() int { 47 | fake.guidMutex.RLock() 48 | defer fake.guidMutex.RUnlock() 49 | return len(fake.guidArgsForCall) 50 | } 51 | 52 | func (fake *FakeGenerator) GuidCalls(stub func(lager.Logger) string) { 53 | fake.guidMutex.Lock() 54 | defer fake.guidMutex.Unlock() 55 | fake.GuidStub = stub 56 | } 57 | 58 | func (fake *FakeGenerator) GuidArgsForCall(i int) lager.Logger { 59 | fake.guidMutex.RLock() 60 | defer fake.guidMutex.RUnlock() 61 | argsForCall := fake.guidArgsForCall[i] 62 | return argsForCall.arg1 63 | } 64 | 65 | func (fake *FakeGenerator) GuidReturns(result1 string) { 66 | fake.guidMutex.Lock() 67 | defer fake.guidMutex.Unlock() 68 | fake.GuidStub = nil 69 | fake.guidReturns = struct { 70 | result1 string 71 | }{result1} 72 | } 73 | 74 | func (fake *FakeGenerator) GuidReturnsOnCall(i int, result1 string) { 75 | fake.guidMutex.Lock() 76 | defer fake.guidMutex.Unlock() 77 | fake.GuidStub = nil 78 | if fake.guidReturnsOnCall == nil { 79 | fake.guidReturnsOnCall = make(map[int]struct { 80 | result1 string 81 | }) 82 | } 83 | fake.guidReturnsOnCall[i] = struct { 84 | result1 string 85 | }{result1} 86 | } 87 | 88 | func (fake *FakeGenerator) Invocations() map[string][][]interface{} { 89 | fake.invocationsMutex.RLock() 90 | defer fake.invocationsMutex.RUnlock() 91 | fake.guidMutex.RLock() 92 | defer fake.guidMutex.RUnlock() 93 | copiedInvocations := map[string][][]interface{}{} 94 | for key, value := range fake.invocations { 95 | copiedInvocations[key] = value 96 | } 97 | return copiedInvocations 98 | } 99 | 100 | func (fake *FakeGenerator) recordInvocation(key string, args []interface{}) { 101 | fake.invocationsMutex.Lock() 102 | defer fake.invocationsMutex.Unlock() 103 | if fake.invocations == nil { 104 | fake.invocations = map[string][][]interface{}{} 105 | } 106 | if fake.invocations[key] == nil { 107 | fake.invocations[key] = [][]interface{}{} 108 | } 109 | fake.invocations[key] = append(fake.invocations[key], args) 110 | } 111 | 112 | var _ guidgen.Generator = new(FakeGenerator) 113 | -------------------------------------------------------------------------------- /guidgen/fakeguidgen/package.go: -------------------------------------------------------------------------------- 1 | package fakeguidgen // import "code.cloudfoundry.org/executor/guidgen/fakeguidgen" 2 | -------------------------------------------------------------------------------- /guidgen/generator.go: -------------------------------------------------------------------------------- 1 | package guidgen 2 | 3 | import ( 4 | "code.cloudfoundry.org/lager/v3" 5 | uuid "github.com/nu7hatch/gouuid" 6 | ) 7 | 8 | var DefaultGenerator Generator = &generator{} 9 | 10 | //go:generate counterfeiter -o fakeguidgen/fake_generator.go . Generator 11 | 12 | type Generator interface { 13 | Guid(lager.Logger) string 14 | } 15 | 16 | type generator struct{} 17 | 18 | func (*generator) Guid(logger lager.Logger) string { 19 | guid, err := uuid.NewV4() 20 | if err != nil { 21 | logger.Fatal("failed-to-generate-guid", err) 22 | } 23 | return guid.String() 24 | } 25 | -------------------------------------------------------------------------------- /guidgen/package.go: -------------------------------------------------------------------------------- 1 | package guidgen // import "code.cloudfoundry.org/executor/guidgen" 2 | -------------------------------------------------------------------------------- /initializer/configuration/configuration_suite_test.go: -------------------------------------------------------------------------------- 1 | package configuration_test 2 | 3 | import ( 4 | . "github.com/onsi/ginkgo/v2" 5 | . "github.com/onsi/gomega" 6 | 7 | "testing" 8 | ) 9 | 10 | func TestConfiguration(t *testing.T) { 11 | RegisterFailHandler(Fail) 12 | RunSpecs(t, "Configuration Suite") 13 | } 14 | -------------------------------------------------------------------------------- /initializer/configuration/configurationfakes/fake_rootfssizer.go: -------------------------------------------------------------------------------- 1 | // Code generated by counterfeiter. DO NOT EDIT. 2 | package configurationfakes 3 | 4 | import ( 5 | "sync" 6 | 7 | "code.cloudfoundry.org/executor/initializer/configuration" 8 | ) 9 | 10 | type FakeRootFSSizer struct { 11 | RootFSSizeFromPathStub func(string) uint64 12 | rootFSSizeFromPathMutex sync.RWMutex 13 | rootFSSizeFromPathArgsForCall []struct { 14 | arg1 string 15 | } 16 | rootFSSizeFromPathReturns struct { 17 | result1 uint64 18 | } 19 | rootFSSizeFromPathReturnsOnCall map[int]struct { 20 | result1 uint64 21 | } 22 | invocations map[string][][]interface{} 23 | invocationsMutex sync.RWMutex 24 | } 25 | 26 | func (fake *FakeRootFSSizer) RootFSSizeFromPath(arg1 string) uint64 { 27 | fake.rootFSSizeFromPathMutex.Lock() 28 | ret, specificReturn := fake.rootFSSizeFromPathReturnsOnCall[len(fake.rootFSSizeFromPathArgsForCall)] 29 | fake.rootFSSizeFromPathArgsForCall = append(fake.rootFSSizeFromPathArgsForCall, struct { 30 | arg1 string 31 | }{arg1}) 32 | stub := fake.RootFSSizeFromPathStub 33 | fakeReturns := fake.rootFSSizeFromPathReturns 34 | fake.recordInvocation("RootFSSizeFromPath", []interface{}{arg1}) 35 | fake.rootFSSizeFromPathMutex.Unlock() 36 | if stub != nil { 37 | return stub(arg1) 38 | } 39 | if specificReturn { 40 | return ret.result1 41 | } 42 | return fakeReturns.result1 43 | } 44 | 45 | func (fake *FakeRootFSSizer) RootFSSizeFromPathCallCount() int { 46 | fake.rootFSSizeFromPathMutex.RLock() 47 | defer fake.rootFSSizeFromPathMutex.RUnlock() 48 | return len(fake.rootFSSizeFromPathArgsForCall) 49 | } 50 | 51 | func (fake *FakeRootFSSizer) RootFSSizeFromPathCalls(stub func(string) uint64) { 52 | fake.rootFSSizeFromPathMutex.Lock() 53 | defer fake.rootFSSizeFromPathMutex.Unlock() 54 | fake.RootFSSizeFromPathStub = stub 55 | } 56 | 57 | func (fake *FakeRootFSSizer) RootFSSizeFromPathArgsForCall(i int) string { 58 | fake.rootFSSizeFromPathMutex.RLock() 59 | defer fake.rootFSSizeFromPathMutex.RUnlock() 60 | argsForCall := fake.rootFSSizeFromPathArgsForCall[i] 61 | return argsForCall.arg1 62 | } 63 | 64 | func (fake *FakeRootFSSizer) RootFSSizeFromPathReturns(result1 uint64) { 65 | fake.rootFSSizeFromPathMutex.Lock() 66 | defer fake.rootFSSizeFromPathMutex.Unlock() 67 | fake.RootFSSizeFromPathStub = nil 68 | fake.rootFSSizeFromPathReturns = struct { 69 | result1 uint64 70 | }{result1} 71 | } 72 | 73 | func (fake *FakeRootFSSizer) RootFSSizeFromPathReturnsOnCall(i int, result1 uint64) { 74 | fake.rootFSSizeFromPathMutex.Lock() 75 | defer fake.rootFSSizeFromPathMutex.Unlock() 76 | fake.RootFSSizeFromPathStub = nil 77 | if fake.rootFSSizeFromPathReturnsOnCall == nil { 78 | fake.rootFSSizeFromPathReturnsOnCall = make(map[int]struct { 79 | result1 uint64 80 | }) 81 | } 82 | fake.rootFSSizeFromPathReturnsOnCall[i] = struct { 83 | result1 uint64 84 | }{result1} 85 | } 86 | 87 | func (fake *FakeRootFSSizer) Invocations() map[string][][]interface{} { 88 | fake.invocationsMutex.RLock() 89 | defer fake.invocationsMutex.RUnlock() 90 | fake.rootFSSizeFromPathMutex.RLock() 91 | defer fake.rootFSSizeFromPathMutex.RUnlock() 92 | copiedInvocations := map[string][][]interface{}{} 93 | for key, value := range fake.invocations { 94 | copiedInvocations[key] = value 95 | } 96 | return copiedInvocations 97 | } 98 | 99 | func (fake *FakeRootFSSizer) recordInvocation(key string, args []interface{}) { 100 | fake.invocationsMutex.Lock() 101 | defer fake.invocationsMutex.Unlock() 102 | if fake.invocations == nil { 103 | fake.invocations = map[string][][]interface{}{} 104 | } 105 | if fake.invocations[key] == nil { 106 | fake.invocations[key] = [][]interface{}{} 107 | } 108 | fake.invocations[key] = append(fake.invocations[key], args) 109 | } 110 | 111 | var _ configuration.RootFSSizer = new(FakeRootFSSizer) 112 | -------------------------------------------------------------------------------- /initializer/configuration/configurationfakes/package.go: -------------------------------------------------------------------------------- 1 | package configurationfakes // import "code.cloudfoundry.org/executor/initializer/configuration/configurationfakes" 2 | -------------------------------------------------------------------------------- /initializer/configuration/package.go: -------------------------------------------------------------------------------- 1 | package configuration // import "code.cloudfoundry.org/executor/initializer/configuration" 2 | -------------------------------------------------------------------------------- /initializer/fakes/fake_cert_pool_retriever.go: -------------------------------------------------------------------------------- 1 | // Code generated by counterfeiter. DO NOT EDIT. 2 | package fakes 3 | 4 | import ( 5 | "crypto/x509" 6 | "sync" 7 | 8 | "code.cloudfoundry.org/executor/initializer" 9 | ) 10 | 11 | type FakeCertPoolRetriever struct { 12 | SystemCertsStub func() (*x509.CertPool, error) 13 | systemCertsMutex sync.RWMutex 14 | systemCertsArgsForCall []struct { 15 | } 16 | systemCertsReturns struct { 17 | result1 *x509.CertPool 18 | result2 error 19 | } 20 | systemCertsReturnsOnCall map[int]struct { 21 | result1 *x509.CertPool 22 | result2 error 23 | } 24 | invocations map[string][][]interface{} 25 | invocationsMutex sync.RWMutex 26 | } 27 | 28 | func (fake *FakeCertPoolRetriever) SystemCerts() (*x509.CertPool, error) { 29 | fake.systemCertsMutex.Lock() 30 | ret, specificReturn := fake.systemCertsReturnsOnCall[len(fake.systemCertsArgsForCall)] 31 | fake.systemCertsArgsForCall = append(fake.systemCertsArgsForCall, struct { 32 | }{}) 33 | stub := fake.SystemCertsStub 34 | fakeReturns := fake.systemCertsReturns 35 | fake.recordInvocation("SystemCerts", []interface{}{}) 36 | fake.systemCertsMutex.Unlock() 37 | if stub != nil { 38 | return stub() 39 | } 40 | if specificReturn { 41 | return ret.result1, ret.result2 42 | } 43 | return fakeReturns.result1, fakeReturns.result2 44 | } 45 | 46 | func (fake *FakeCertPoolRetriever) SystemCertsCallCount() int { 47 | fake.systemCertsMutex.RLock() 48 | defer fake.systemCertsMutex.RUnlock() 49 | return len(fake.systemCertsArgsForCall) 50 | } 51 | 52 | func (fake *FakeCertPoolRetriever) SystemCertsCalls(stub func() (*x509.CertPool, error)) { 53 | fake.systemCertsMutex.Lock() 54 | defer fake.systemCertsMutex.Unlock() 55 | fake.SystemCertsStub = stub 56 | } 57 | 58 | func (fake *FakeCertPoolRetriever) SystemCertsReturns(result1 *x509.CertPool, result2 error) { 59 | fake.systemCertsMutex.Lock() 60 | defer fake.systemCertsMutex.Unlock() 61 | fake.SystemCertsStub = nil 62 | fake.systemCertsReturns = struct { 63 | result1 *x509.CertPool 64 | result2 error 65 | }{result1, result2} 66 | } 67 | 68 | func (fake *FakeCertPoolRetriever) SystemCertsReturnsOnCall(i int, result1 *x509.CertPool, result2 error) { 69 | fake.systemCertsMutex.Lock() 70 | defer fake.systemCertsMutex.Unlock() 71 | fake.SystemCertsStub = nil 72 | if fake.systemCertsReturnsOnCall == nil { 73 | fake.systemCertsReturnsOnCall = make(map[int]struct { 74 | result1 *x509.CertPool 75 | result2 error 76 | }) 77 | } 78 | fake.systemCertsReturnsOnCall[i] = struct { 79 | result1 *x509.CertPool 80 | result2 error 81 | }{result1, result2} 82 | } 83 | 84 | func (fake *FakeCertPoolRetriever) Invocations() map[string][][]interface{} { 85 | fake.invocationsMutex.RLock() 86 | defer fake.invocationsMutex.RUnlock() 87 | fake.systemCertsMutex.RLock() 88 | defer fake.systemCertsMutex.RUnlock() 89 | copiedInvocations := map[string][][]interface{}{} 90 | for key, value := range fake.invocations { 91 | copiedInvocations[key] = value 92 | } 93 | return copiedInvocations 94 | } 95 | 96 | func (fake *FakeCertPoolRetriever) recordInvocation(key string, args []interface{}) { 97 | fake.invocationsMutex.Lock() 98 | defer fake.invocationsMutex.Unlock() 99 | if fake.invocations == nil { 100 | fake.invocations = map[string][][]interface{}{} 101 | } 102 | if fake.invocations[key] == nil { 103 | fake.invocations[key] = [][]interface{}{} 104 | } 105 | fake.invocations[key] = append(fake.invocations[key], args) 106 | } 107 | 108 | var _ initializer.CertPoolRetriever = new(FakeCertPoolRetriever) 109 | -------------------------------------------------------------------------------- /initializer/fakes/package.go: -------------------------------------------------------------------------------- 1 | package fakes // import "code.cloudfoundry.org/executor/initializer/fakes" 2 | -------------------------------------------------------------------------------- /initializer/fixtures/ca-certs: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIBdzCCASOgAwIBAgIBADALBgkqhkiG9w0BAQUwEjEQMA4GA1UEChMHQWNtZSBD 3 | bzAeFw03MDAxMDEwMDAwMDBaFw00OTEyMzEyMzU5NTlaMBIxEDAOBgNVBAoTB0Fj 4 | bWUgQ28wWjALBgkqhkiG9w0BAQEDSwAwSAJBAN55NcYKZeInyTuhcCwFMhDHCmwa 5 | IUSdtXdcbItRB/yfXGBhiex00IaLXQnSU+QZPRZWYqeTEbFSgihqi1PUDy8CAwEA 6 | AaNoMGYwDgYDVR0PAQH/BAQDAgCkMBMGA1UdJQQMMAoGCCsGAQUFBwMBMA8GA1Ud 7 | EwEB/wQFMAMBAf8wLgYDVR0RBCcwJYILZXhhbXBsZS5jb22HBH8AAAGHEAAAAAAA 8 | AAAAAAAAAAAAAAEwCwYJKoZIhvcNAQEFA0EAAoQn/ytgqpiLcZu9XKbCJsJcvkgk 9 | Se6AbGXgSlq+ZCEVo0qIwSgeBqmsJxUu7NCSOwVJLYNEBO2DtIxoYVk+MA== 10 | -----END CERTIFICATE----- 11 | -----BEGIN CERTIFICATE----- 12 | MIIFATCCAuugAwIBAgIBATALBgkqhkiG9w0BAQswEjEQMA4GA1UEAxMHZGllZ29D 13 | QTAeFw0xNjAyMTYyMTU1MzNaFw0yNjAyMTYyMTU1NDZaMBIxEDAOBgNVBAMTB2Rp 14 | ZWdvQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC7N7lGx7QGqkMd 15 | wjqgkr09CPoV3HW+GL+YOPajf//CCo15t3mLu9Npv7O7ecb+g/6DxEOtHFpQBSbQ 16 | igzHZkdlBJEGknwH2bsZ4wcVT2vcv2XPAIMDrnT7VuF1S2XD7BJK3n6BeXkFsVPA 17 | OUjC/v0pM/rCFRId5CwtRD/0IHFC/qgEtFQx+zejXXEn1AJMzvNNJ3B0bd8VQGEX 18 | ppemZXS1QvTP7/j2h7fJjosyoL6+76k4mcoScmWFNJHKcG4qcAh8rdnDlw+hJ+5S 19 | z73CadYI2BTnlZ/fxEcsZ/kcteFSf0mFpMYX6vs9/us/rgGwjUNzg+JlzvF43TYY 20 | VQ+TRkFUYHhDv3xwuRHnPNe0Nm30esKpqvbSXtoS6jcnpHn9tMOU0+4NW4aEdy9s 21 | 7l4lcGyih4qZfHbYTsRDk1Nrq5EzQbhlZSPC3nxMrLxXri7j22rVCY/Rj9IgAxwC 22 | R3KcCdADGJeNOw44bK/BsRrB+Hxs9yNpXc2V2dez+w3hKNuzyk7WydC3fgXxX6x8 23 | 66xnlhFGor7fvM0OSMtGUBD16igh4ySdDiEMNUljqQ1DuMglT1eGdg+Kh+1YYWpz 24 | v3JkNTX96C80IivbZyunZ2CczFhW2HlGWZLwNKeuM0hxt6AmiEa+KJQkx73dfg3L 25 | tkDWWp9TXERPI/6Y2696INi0wElBUQIDAQABo2YwZDAOBgNVHQ8BAf8EBAMCAAYw 26 | EgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQU5xGtUKEzsfGmk/Siqo4fgAMs 27 | TBwwHwYDVR0jBBgwFoAU5xGtUKEzsfGmk/Siqo4fgAMsTBwwCwYJKoZIhvcNAQEL 28 | A4ICAQBkWgWl2t5fd4PZ1abpSQNAtsb2lfkkpxcKw+Osn9MeGpcrZjP8XoVTxtUs 29 | GMpeVn2dUYY1sxkVgUZ0Epsgl7eZDK1jn6QfWIjltlHvDtJMh0OrxmdJUuHTGIHc 30 | lsI9NGQRUtbyFHmy6jwIF7q925OmPQ/A6Xgkb45VUJDGNwOMUL5I9LbdBXcjmx6F 31 | ZifEON3wxDBVMIAoS/mZYjP4zy2k1qE2FHoitwDccnCG5Wya+AHdZv/ZlfJcuMtU 32 | U82oyHOctH29BPwASs3E1HUKof6uxJI+Y1M2kBDeuDS7DWiTt3JIVCjewIIhyYYw 33 | uTPbQglqhqHr1RWohliDmKSroIil68s42An0fv9sUr0Btf4itKS1gTb4rNiKTZC/ 34 | 8sLKs+CA5MB+F8lCllGGFfv1RFiUZBQs9+YEE+ru+yJw39lHeZQsEUgHbLjbVHs1 35 | WFqiKTO8VKl1/eGwG0l9dI26qisIAa/I7kLjlqboKycGDmAAarsmcJBLPzS+ytiu 36 | hoxA/fLhSWJvPXbdGemXLWQGf5DLN/8QGB63Rjp9WC3HhwSoU0NvmNmHoh+AdRRT 37 | dYbCU/DMZjsv+Pt9flhj7ELLo+WKHyI767hJSq9A7IT3GzFt8iGiEAt1qj2yS0DX 38 | 36hwbfc1Gh/8nKgFeLmPOlBfKncjTjL2FvBNap6a8tVHXO9FvQ== 39 | -----END CERTIFICATE----- 40 | -------------------------------------------------------------------------------- /initializer/fixtures/ca-certs-empty: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudfoundry/executor/78ff519666b527dac7465515c43f3a058f278419/initializer/fixtures/ca-certs-empty -------------------------------------------------------------------------------- /initializer/fixtures/ca-certs-invalid: -------------------------------------------------------------------------------- 1 | invalid cert bundle 2 | -------------------------------------------------------------------------------- /initializer/fixtures/ca-certs-with-spaces.crt: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -----BEGIN CERTIFICATE----- 5 | MIIE/jCCAuagAwIBAgIBATANBgkqhkiG9w0BAQsFADAfMR0wGwYDVQQDExRjYS1j 6 | ZXJ0cy13aXRoLXNwYWNlczAeFw0xNzA0MjQxNzQ4MjBaFw0yNzA0MjQxNzQ4MjNa 7 | MB8xHTAbBgNVBAMTFGNhLWNlcnRzLXdpdGgtc3BhY2VzMIICIjANBgkqhkiG9w0B 8 | AQEFAAOCAg8AMIICCgKCAgEA22ndMdXFVijHE6CTO51mWxAOqIIjsBkyfXJaEJ1I 9 | /xxJCA7T8AyVLNe6vZEE8Lc8dytH7tTQXu9VJreczt2e9l/7UlmnoaMWxZTNjkNP 10 | 5Zpchx41Ml2LnPRJkLsfanKbioeNiIgVOTxKqiZDWbOkp5xdc90T2ecN+IBZBEZr 11 | 7KJXIbTQuYI74Z+mMSuALdyMI01Qv7hvqgDp+vVolqfW4T1rnRzQkwkeE4NHmbyW 12 | 0QXEgiKAAgNejCcXjYhIZVK3aoBmuwG5hZA1lu1DZnzfbIc8Oi6QpfvB0jf/+zPD 13 | C4WQ3Flx6nWweohIFXo7Zfp51L0oQJGySRhKKgADvkCAuOP9jza2ihAv+Q/bb2F3 14 | Fn684ZhWmofwk25TlS6q2KO7nWdhbavkWeMybtY4vpoT6C+dz8QT4CMHfwLHQNOU 15 | zCP7xggmO2dpNBBvS/9tk+i1g98q5h1svUMk3hqHeCuyfKwjHbi39m4gJrnbWk95 16 | f4IhS6G5YtvXImjr7P8nud/A4nZIV/NGG1FWIIVPtm9CScvbPbkuM/F5YZoPY9rt 17 | slKa0og7IzTSK7Ov93R7bD7G47QEa1A5R5uk2jLFXrVyckYZrAM27AyH+N/sa/Jj 18 | foMrHu+/WzRNwGKuDraQiGclOpqk2sjSNpkc0gDG8ZbCq1g1ioG9r6Yu2gCAsW/n 19 | GpMCAwEAAaNFMEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAw 20 | HQYDVR0OBBYEFEpIsjvRk7rBgl/i3m/fNnbLFo6rMA0GCSqGSIb3DQEBCwUAA4IC 21 | AQDY9/eMbAA1cgZjsWN16NHWYMwPHNr0Wjq/QO38VwwFF1bmmcMXctaHAAaxHdF5 22 | 812Tl4dKNcEqOhlTs5W7F2pVokhA8wpK+QuoFkI8Cc5EF35IglONA+ZEtFR5Wcah 23 | r9hiM4EGeTV6/OblpQ/Pl2CO6JJfeNdplkm3sM/j/KzN0zgf9C4epTkN1CPLnF12 24 | dkNhTWBLwF/Jl7YdA0mgdBl+kN6TfJ9X9v8o3M8LyFruG+Q42zuvUz3HrlXtIigg 25 | RaW9t9nMTm+t7vppNJn2V0YvrNxsE/u3MncQfW3VmAjgm6r6MH/zFAtq0HeIgIwG 26 | ojnffZhl9M4cDrM3Ul8MYKb4gB+K1kQ3Vfu+vDdv5LI/9g9xAcRcfXPgHGwS4fHx 27 | gJN5ydlis9qR6f55dZWi/P+1IV1V2+QocKbMLee8Kc5UKXcf5C+7VXs6Y+FzujH/ 28 | ZflGCPZPjW/XqX3pDtTKaYUbdVJiHz6yqQhN12DO/gfaSCwLTTkJmOqe0EIAO7kw 29 | iPoBSDdTjPf6cVOdMmOe9hVP1pPUCXSK4ONbednzu0Wo0IvQ0ZBXGU6S4o+vfHAu 30 | vKjs/G/mFvMTpiZ4biQ6sEmjsIyP7uqABRxOkBQERxQWa67OQgpvrI1bejWmIgQw 31 | 8/afZTSQEoYPgZLWqQNT6Tw43XlW4D1p9+Ix/kc5k55aCg== 32 | -----END CERTIFICATE----- 33 | 34 | -------------------------------------------------------------------------------- /initializer/fixtures/downloader/ca.crl: -------------------------------------------------------------------------------- 1 | -----BEGIN X509 CRL----- 2 | MIICfDBmAgEBMA0GCSqGSIb3DQEBCwUAMA0xCzAJBgNVBAMTAmNhFw0yNTAzMTIx 3 | OTIzMTlaFw0yNjA5MTIxOTIzMThaMACgIzAhMB8GA1UdIwQYMBaAFI6CKzcbHroW 4 | rnTkepGL7oSVPSP9MA0GCSqGSIb3DQEBCwUAA4ICAQDBc7ctJIYAUsBfiHfl7JUq 5 | d/Iy8PjzOBEC11vwRfoUiHKURnRWqqhoY7HKkwkuQ+OW0CVSq72yNtSSYoctP49k 6 | yoEi61gu98BJyVrMpXDz7sPYxkmXvgdhYevXPx3me69W/GKy5fJ+JL9MFwn/X2XS 7 | bzQzPEEF7r9PmMZ95x1qQUjWz7A1zDiPNDinBMcyTtHJf8RV80cA83njEbj+dk3l 8 | AaTaC5hugfVZOICgb7ymJXrJ+nJRbEFQO7GR/huEHTlm5L1nx59k2hG+icf7RVSo 9 | JEky3IGxxztNEUR2r8hH9/KsD8DsQt0qu4k1Nsfz7pxrAZlwsAR4upLGzaQtS2Wp 10 | qF8q9XJkNzkqFUnVy4UvMNbTw0cQhOFte4WsYL4egPD5trew5GWjbprKt7AVcSSA 11 | FLVD1Bgwq/H0lKFLaAQ9RSxTsKyisnVSVXJw9QTIoXWHM0oUjqdMyMsilEnxY9OP 12 | 7yOs1mjytQv7yy+uhbAuBvRrAEC4g5wbihRUDBN9B4ojPOSQ6itci/T4euBq2Oed 13 | TVyf4oz1jp/4Ve74k8qeu2I+J6nAUilE6xnqLK+pMwuA9wP/ciu7OhTE/rnYn9rN 14 | he+PlgyGeq+YnKR1oqe1+DvWI43AUK7/xMr7ja1lWSOW11ZLoZ7hQJk9ty+vIw9K 15 | to1vY3Exe+fg1xGY6az+gg== 16 | -----END X509 CRL----- 17 | -------------------------------------------------------------------------------- /initializer/fixtures/downloader/ca.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIE2jCCAsKgAwIBAgIBATANBgkqhkiG9w0BAQsFADANMQswCQYDVQQDEwJjYTAe 3 | Fw0yNTAzMTIxOTEzMTlaFw0yNjA5MTIxOTIzMThaMA0xCzAJBgNVBAMTAmNhMIIC 4 | IjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA7wH1inuthD3mYyn0kti9Bq9C 5 | 2gk86ZDlqySs5a1Jk3UKYOjNnZ58ZW5qSjdFLFRKx5sTeCqn7PeaNPts6i8iWyvh 6 | n1HZaeiCldnM1mU3uMpK3wknICb9Z6Ygx2wW1gQCfcSwYoFNf5wpC25uF3LUrIKJ 7 | MWCslDgqnJvwu/amUwmjzcOX4VyOYWA29ABpZr9QzJuXswP7cN9+Om81kIPDDRet 8 | L+nMy+iaEP5vVJrlIw4xCqYyowjbfvJd3yvH6H2kJeJTWgA202VcUkiCMPV2PV0U 9 | +rRb3zROxFrtoyfw3S4c2nW84WuOgjosZKve5vTFi8lJTQ3ChasjTZEgyMKnyf7X 10 | r4AKhmWR1R8sYJdPQoozK3BwPXvzIsjhzL96UVcQWYAeDcq5R3bvSa0F3H01KLlO 11 | czjaLkW9DK45EHbs85rW8gNIp4Ug2A6VxpTQmiy8dYgw+0ii4BzcreMW1Xj+b0gd 12 | 8+NVejSUoBtbqkluIwdgPUbl6ZTwwyKex+dFIlm9cEWmFbI+3av+shrYKpKq9FBm 13 | JSys00CUZWkxdnzvotAnT6lZDvL/RoPu1wLpIEbN9yaTehXwRHGNrsR5+jbn0ROz 14 | DSKe2IV7+bLHnsxPfOTiSnI+hTzOmdhrNQ0LaZ303Clak6rZKmQjgKb/JVnJdL+L 15 | wHNmoc8W6P9r5P1Y+VsCAwEAAaNFMEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB 16 | /wQIMAYBAf8CAQAwHQYDVR0OBBYEFI6CKzcbHroWrnTkepGL7oSVPSP9MA0GCSqG 17 | SIb3DQEBCwUAA4ICAQCsandnziPM03GtKyUN/pNLFeBflEjjY2LIl0om4EJzx6VV 18 | DhySmB72Dy4Zf2fmOnfH8ROI2+8Sl0bikTc/X/WjSYlUXfLMTjhisf2UyAhSetuF 19 | wMxwpaNHtXhqTkb5HdFkpN7uOsRh+m/u4ppNysrIFEFZ/Y2PCv7aEcjCcdMFHaHw 20 | 3KYoCOgxSp7YxrwuOsjC4zNlcDHdbF0hAJbjCU6Z/KlK9aIobdgSXEY/Rjmtz+5T 21 | 1a1epdqhc3Aoll+lPT1kVB3Sq9mTF7bgmJLKK6hTtcEAbkR0/oBPjs1QNuXtcmTl 22 | b2QUtYWbmSQGehsNUoXV2kEJoOmFGpbLG5iWaE4kcAx4stMq6A8M7yQ5UkRzbism 23 | XHZSlRTXUcSI+YLld5wEkNlkdzuvlSMTEvLGl4cOCiMYfbaQbl1hvI5OXdZxWFGO 24 | fBRZtN1fKitLS7BZXSVW4zdJCQBXWmqZ3Xllc3N2R2+8Mp55ve63YA5q24Vk49MG 25 | T2QT1D9Qsir53rArhz9GwMw552TTqKzdenji1qbd74MSi6uAqnd7XSa/KC+uNGZg 26 | La/zx5pNsRimzEBzB+63JR6TRn037Iv9JQ1pr9TEVrJSTch9JinATI7OH/HROV7G 27 | BAFz1KDRHHDeermHxGU1lwSucS+mASUBL39NEz5nYmmYpwi6ziFWU4hVmaGEPg== 28 | -----END CERTIFICATE----- 29 | -------------------------------------------------------------------------------- /initializer/fixtures/downloader/ca.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIJKgIBAAKCAgEA7wH1inuthD3mYyn0kti9Bq9C2gk86ZDlqySs5a1Jk3UKYOjN 3 | nZ58ZW5qSjdFLFRKx5sTeCqn7PeaNPts6i8iWyvhn1HZaeiCldnM1mU3uMpK3wkn 4 | ICb9Z6Ygx2wW1gQCfcSwYoFNf5wpC25uF3LUrIKJMWCslDgqnJvwu/amUwmjzcOX 5 | 4VyOYWA29ABpZr9QzJuXswP7cN9+Om81kIPDDRetL+nMy+iaEP5vVJrlIw4xCqYy 6 | owjbfvJd3yvH6H2kJeJTWgA202VcUkiCMPV2PV0U+rRb3zROxFrtoyfw3S4c2nW8 7 | 4WuOgjosZKve5vTFi8lJTQ3ChasjTZEgyMKnyf7Xr4AKhmWR1R8sYJdPQoozK3Bw 8 | PXvzIsjhzL96UVcQWYAeDcq5R3bvSa0F3H01KLlOczjaLkW9DK45EHbs85rW8gNI 9 | p4Ug2A6VxpTQmiy8dYgw+0ii4BzcreMW1Xj+b0gd8+NVejSUoBtbqkluIwdgPUbl 10 | 6ZTwwyKex+dFIlm9cEWmFbI+3av+shrYKpKq9FBmJSys00CUZWkxdnzvotAnT6lZ 11 | DvL/RoPu1wLpIEbN9yaTehXwRHGNrsR5+jbn0ROzDSKe2IV7+bLHnsxPfOTiSnI+ 12 | hTzOmdhrNQ0LaZ303Clak6rZKmQjgKb/JVnJdL+LwHNmoc8W6P9r5P1Y+VsCAwEA 13 | AQKCAgEAgvfH3QK4qmZhAKXU50LtEeSn9WJqhnJn58hJFfJHBw5ziXcIdP6Lm+lN 14 | RS3UMd5eu9I2cPqu2iMz1SSRIiKB6QO6ttrbEDXgmMyoejMsvY3cSStyzSOQaGOY 15 | Qq7wNIYt90z4eoHwPaUMuL7ihObfs0g0dWJML0w3zWmGGPmnWolFwVMUvuFBBAr9 16 | EefH2g2r8PKxxd7AwbE2Mj8OUwpgr6PxuveayYHEKtvBldLrDLKSHQvFY6FO5dlZ 17 | pxkOik+Oy1Oh6QeFA4HffRdOgBWBnU6MWHTMgxrerqpE3crdKdZC6VLrFXsitCm8 18 | ec3UbyphtZ+vExIfLbABwFduZ5SC7BYIks2AMr3bkJ3jFNtsGIWpX/4aB6hftrRC 19 | zyE6y7Qh2ajld5S2sdIZWWHJp9TqkJuEOPWE2bJbzt1sdO7wnBnHqVKs6+i+NGOV 20 | CNv9KBg3e4fjl+/y7CimzoA1475bOiXd+OhvBzCboC9cBiLkqgnMwMhh1yvQG6Dr 21 | 9USkIyC/1M1GIGsLZ1n09dlGsfjEaoQnMOWBzlk8X6rXcsImSzZOhQv1URUhT3UD 22 | gpHvcD1HjKygqsf+0dFo0gZQfuSD28DZc1khF0jWXgCAy7sXkEgaG8z/ln88dB2C 23 | l4YY4qeYR521qFY34JkS60zjC1JEZXzR9DovsEnrvQq3aOwYRMECggEBAP8tDFHd 24 | PoHNL1+/fIteRr/Rf32vwC6pUJgtVpz566e11/29GQvoFzQkHC4wsalX837vIkf1 25 | VDQvAIiJZux/9lr6FP5s37yakrea4CAgZoiUb3f5UegNjjxtgRgay2893RygmXGs 26 | SF735IDXHwGZmJf+BApoSVTmnZ8sXOEMPwBwVTv41xrmTrcG4Ru8cghihQ6lnhEf 27 | rrlpQmcq7/Xlx3DpbL1ucM2YhDnIl4fUoQzq+bgfEj+HqLtUq982dU2QQECY1C+F 28 | n10wPwMOTa7ytqp4Hluupx1RCh+ynAW/zqjb5pUlppPyH+SYYo+jPvcRpcHNvlsC 29 | 0w6muhKASou7mTUCggEBAO/Hi3hoBKrPGDF0oIkrLmtNRbND13JN4GtDH0B8Fb0r 30 | /I6IMCc/jHhSFPNvEzpiRcenbNC+4GeDqNooNAnJlN7jSRIom4vGOFMXjcT/jlW+ 31 | 1jiZhf6WminAY6k/3+vDP2n9519MWvRUlh1eH/YIHcAHwh/mnkVZMRU21h6Bmc31 32 | wXeMpAlC3t9S1b4QSsO40F85OH04tpzgevN9VSEtsILQp0CWLhFsqD1amlhV5Ja6 33 | 8TKYDXFmbaGd3rBS0pr3L51m1qvlRH4GrR8qbkkUYaH2COh1fuTmwTVHs/DhWzJE 34 | l3CGxpFXOV5iigwURVtdBXHMfGQ1p3Kfd5cs0VZKKk8CggEBAL3cTMBUd3+opUj+ 35 | drJTsRxjyhJARCPzwo2Xnkwp/9bHDDA1FH+xbiJTg8wyWt3/HKMjVkRoGwDAwArX 36 | AQeSpkBGtnwfkdEIyYVm7L+6m8+fcdi4XuLjwyLe7yB6P0dDplL4g3L6ltZiZ1gd 37 | t2o/WDQuwd7kfTt4Y2rdXTXtIKs46ZI3sgTHu2We7rruWYI3m3ysaZGgGybFVKzi 38 | W6yADQbMByZjF/dBNZCw2V4tLK8p3ifKpo8yZq8Lbt4j7N+LJuNpUucQ6uQxU5D4 39 | gYBcAuGPgjcBGkJL29Z91GzKq/8jrsrmOqz1iBlT8HGjKuQ18zjh1nJtBZBvKR8+ 40 | 6ThSmskCggEACO1c+/ajddiQBgdZksHQ0J3n4my8ML1FhbjSCQyVop1oocXgRRXQ 41 | nQoxTX7tMFdIUc6h9oOkxzXXq4ejqFmg+UttBQgOAn42yqEt3g/FtNuODj1pB7mD 42 | s9o926dNJvH2AnQ5kQq+uCoODLncZsSWlvey+o0Th3Fyql+ISUp593kW4uSRluau 43 | dZIX8yOYJQFUgLcYq1DZO63/5eDcsoeI8tXh5D2zKWLqQJ6G8JMCF7qOEFwo4/f0 44 | TPgbumTbAnoBg9K4W14F1stY1rg1svLXT7hhTIZTWyJcPyeUQ3ugcZasLLxX2EFv 45 | GVyB10FJ88Ta1wnN980nltTpFu/MO3I3cQKCAQEA6T1Vy7laLj7cx3pYOqIsLvQd 46 | NVJO17HhYz9h4v4Z6MGWPU//IkcKd+awToIBK+YchACn87m4UYGlZkVzNT+fNtZM 47 | 2GbTnqo0RGuOX4nViC/xRhQS+itEn/stIvOeuVjUjKwV6iaCXVN0boWXgz2/vA/A 48 | Oukz8/jpuKQD3qCVHrgKEat1JGWCsUIYpD/ckMkeNevk0JV5K/Te+E6+2FMox/Ga 49 | wRWeDVykEl8UpLUZY4V+6dvJLP4bOzv47j9y37IvQ5X4fpIHE7tcHCJIUqzK9Nrg 50 | BcU0CHuM/YhuiUl/Sp21q3zUaJNO82DIH5+sM30cM67ITEG71r5DRTkjzHxjTQ== 51 | -----END RSA PRIVATE KEY----- 52 | -------------------------------------------------------------------------------- /initializer/fixtures/downloader/client.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIEGTCCAgGgAwIBAgIQaqqbv2N9m9o3ww9f4ZSOuzANBgkqhkiG9w0BAQsFADAN 3 | MQswCQYDVQQDEwJjYTAeFw0yNTAzMTIxOTEzMjBaFw0yNjA5MTIxOTIzMTdaMBEx 4 | DzANBgNVBAMTBmNsaWVudDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB 5 | AMUTj14273mtlyHFqsFZRamJwuyxhNsdtuAlkPYfJ3CeRrhdWjM/o2YraUXzZebW 6 | F52tjFUzpE/Mem0jLkhzTc80gaHONQx/YsvR8dyswhOlMby9JCM/ch453LMyITzu 7 | 3x7HMKF+IS50czAaEjWlhRe90rHbVBjOqfVgZ20HAfdgRA+QR9wU8kI1D9rZRvGq 8 | FihLKJMqVYJHEdema1tybi37oebHJWZP16M7T7aAwNa99s+7TV1lcqXekJq6dCgs 9 | rBZk4C2JD8yP/oQKu05dQEORxTSpDpQpEh7NzdL1WqsoFo5RXnvwWHPJaeBSFGk+ 10 | prPtnc9LMEKfem1W1wYyDRMCAwEAAaNxMG8wDgYDVR0PAQH/BAQDAgO4MB0GA1Ud 11 | JQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAdBgNVHQ4EFgQUhcsXarHRfMp4Oemy 12 | f+0juZ9QbO4wHwYDVR0jBBgwFoAUjoIrNxseuhaudOR6kYvuhJU9I/0wDQYJKoZI 13 | hvcNAQELBQADggIBAElHoN9zlSBzTLNBJJ3BGQe9MUSu+9SngPf+w95+s31jZt6l 14 | i1uHxT6uxXJzS0zMr+Wa1xl4upuVhbasVDOivBn8twXN0naHrr553zABOdHJ1Gt6 15 | tk1QshD3hQbk0wQ1TqyudENe7tO9O2wuXQhO9cGUcG56VmYO3wexQ/dZBwjyWvkb 16 | jNSTaUh+Ne1NWQFM93D4vsARVXTOJ/0HyIu5qHdHDyoqEtFLFLP3CGqR73VsKbLk 17 | jXeAaIIZHqH13CYBrcdNZP2od84wj0HjLQILayseP7nyLTaHe4rE+d4VEb34EOFH 18 | NS3XeclVICboil7vlJP2HpCVbV/og/Medv09HKsfNtpuVwr5IeXTUptX8ug+MP8C 19 | S1Tl590dEw8Aa4DpcrAjSgcDA/LjEkb/xyY7Gq5FgKD6CG5Qq02pLqXbLQ2MjMij 20 | oHNWBVU/pJIUummaTArLd9A9wCZ91W+iUfa+3mG8cUF5piAIdNrTpvOJG7VksFUg 21 | 4bOg30mkCfebgX1IR/oePfb4kcuxIABqufFIoQ0e7rxYliO0UZPoWw/Q9JCRy/qD 22 | SWxD1L8yNSfwprfXExMUqQ02+GZAx7yOsJG3xKXpSRqqT+LPYXO/nvqsGh3tv6KY 23 | +1cZxI/8ZTMAfLy/m+60lo4vsDG/4TCGe2hIU6UJwFt1SyXl+uBReEY9V5ki 24 | -----END CERTIFICATE----- 25 | -------------------------------------------------------------------------------- /initializer/fixtures/downloader/client.csr: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE REQUEST----- 2 | MIICVjCCAT4CAQAwETEPMA0GA1UEAxMGY2xpZW50MIIBIjANBgkqhkiG9w0BAQEF 3 | AAOCAQ8AMIIBCgKCAQEAxROPXjbvea2XIcWqwVlFqYnC7LGE2x224CWQ9h8ncJ5G 4 | uF1aMz+jZitpRfNl5tYXna2MVTOkT8x6bSMuSHNNzzSBoc41DH9iy9Hx3KzCE6Ux 5 | vL0kIz9yHjncszIhPO7fHscwoX4hLnRzMBoSNaWFF73SsdtUGM6p9WBnbQcB92BE 6 | D5BH3BTyQjUP2tlG8aoWKEsokypVgkcR16ZrW3JuLfuh5sclZk/XoztPtoDA1r32 7 | z7tNXWVypd6Qmrp0KCysFmTgLYkPzI/+hAq7Tl1AQ5HFNKkOlCkSHs3N0vVaqygW 8 | jlFee/BYc8lp4FIUaT6ms+2dz0swQp96bVbXBjINEwIDAQABoAAwDQYJKoZIhvcN 9 | AQELBQADggEBAHEA/AU2BV3w8rSlEXcpTt3CdOXTpln4bB76fP5Q3FjnqtNDkM/2 10 | P8Z+KFfzZJ2yDhA630dvqWqTbEzfb0+BxkaXVYV18ltRmCIR/u1G6TZwd78pIbY3 11 | cBgNqCoB/8NnnqqXmlyFCGk36zbntwAwFnFjAt0wWBjq5oJ7TYmV/Ode/f1IBwNy 12 | iaFgf+tv3CUK1WKfLrTZEKMhmHQBXZuXZNAmI0T6Tr8swt0XPh3CUCVxf9eW/C9B 13 | PQkbbJs+GYrsSFtyovgSrekB/kdw8ZWL+1/oa3Op1hfpnj7bZWyYs8FYEEoLGvfU 14 | KSD/joWUti8CfGhT8MqSUpCoIMvOHCS+ud8= 15 | -----END CERTIFICATE REQUEST----- 16 | -------------------------------------------------------------------------------- /initializer/fixtures/downloader/client.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEogIBAAKCAQEAxROPXjbvea2XIcWqwVlFqYnC7LGE2x224CWQ9h8ncJ5GuF1a 3 | Mz+jZitpRfNl5tYXna2MVTOkT8x6bSMuSHNNzzSBoc41DH9iy9Hx3KzCE6UxvL0k 4 | Iz9yHjncszIhPO7fHscwoX4hLnRzMBoSNaWFF73SsdtUGM6p9WBnbQcB92BED5BH 5 | 3BTyQjUP2tlG8aoWKEsokypVgkcR16ZrW3JuLfuh5sclZk/XoztPtoDA1r32z7tN 6 | XWVypd6Qmrp0KCysFmTgLYkPzI/+hAq7Tl1AQ5HFNKkOlCkSHs3N0vVaqygWjlFe 7 | e/BYc8lp4FIUaT6ms+2dz0swQp96bVbXBjINEwIDAQABAoIBAGSTVOl6E8D/TE/Z 8 | 9wjxrFGXkrkE546DnZ7KzS4uPAyHWgQg8DWTVqp/oRwn2Wty+15nAWVCE6r96cTk 9 | 3WvwHFeQrk+LUxtrr1nhbRN3vxwThEyUImsyp+SxFucEwF2+cnPcp/7ixcBVgauc 10 | wopKTKAPKgXGryZx4d7uMho8J069FT0YtlpHXYQD2MgjbcBibe1WOFohvGG/C1Rx 11 | Fx0XOq/+xhNO3NdMpIZXZD1lNGdEQSHfEH2xwXnkko52e+L2mMNBi5I9MNg2fygD 12 | 3EO/0EEb9mCYgtlNuo+cKKgKZI4zqmvR0UH1oZsryES3rF7i6lKAdptXPQ2XXJIq 13 | IrCEyqECgYEA/hgotTcWYpCgqutFS/lxx74sLG49olnV7I+vDEV4291ZWl1MXpL7 14 | JkbayqKiQp5Fsi402qjAqnuoBGMhtvdEh+8bm8Zz2XkHi4IPMfGJ7SazM0jxO9KP 15 | D0abhHGAGyB7lzTicyMd+FSsHtReDpb5tRhezm50RdBBIPq+OtgiFVkCgYEAxo3u 16 | WdfhlZeTaJBjwpsk9EvumREF8HDepxVyIbqc0gyXwxrLMJbKZjxWZYldPzk3AYTC 17 | bE0NAcHbNxhn31UrGgVA6vk1rDhCPC9ZNKZR4MSxM0P6injaMx3UBC+TXsvuZQ2/ 18 | VzXtbbGef8eiBfxH19U/qGuWS/BOcWDJh1sOrEsCgYB7gmLHMy++WW6/pfzZITcd 19 | UGNIdY2gDOrfQjhkTqCgvsdgFVm53tgVkvtm5AbbOvPF2I/4eW6tb84L0+Pfe/Hj 20 | 4WYaIizN2PbB6UZZkH7qt5UDqMEZww+m7TtK9aC/jtqEdUBdlwRKYV4I3lGZ5ekb 21 | De2HikkaZlBCJ5+wGr72gQKBgGhygx655I4XtVB9HC1kBZWJWBMnFFO+XDHSoz5A 22 | 93u7ah4VOyvtNr1/Ige5sdavV1MyLkBga+YvvwyFhybBm7HNb6/rtqNI2PbmBWwf 23 | zdSKQ5jvOp2bI1VebIhjKofkiRyZlbzfvm1E0VbwgjfZ1UUhhaIoLmD2IZ2cx4av 24 | jNFvAoGAOK5ugE0QTGLYQK2qHd/EYtb9WdcfvcgxBAS9IYubbMthSoafsVkiJq/3 25 | Y337oIGKoIGrLRdKUtw5zq5EtbfB+xQg9DziyJGBEtQOerORY7izz/Y7zRdFkwNR 26 | Y5nc1wh4kLE/Tt+sXcrhslgYKjmuxwQCJtxsFM6pkP2kgbt3MwY= 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /initializer/fixtures/instance-id/ca.crl: -------------------------------------------------------------------------------- 1 | -----BEGIN X509 CRL----- 2 | MIICfDBmAgEBMA0GCSqGSIb3DQEBCwUAMA0xCzAJBgNVBAMTAmNhFw0yNTAzMTIx 3 | OTIzMThaFw0yNjA5MTIxOTIzMTdaMACgIzAhMB8GA1UdIwQYMBaAFEW1NttB5iss 4 | i+R/FGweLN8wN/taMA0GCSqGSIb3DQEBCwUAA4ICAQCKJfpaJW9vT3wy438A6gXS 5 | ST4mHbiegmVLc/IZpU5U426J+7Xs5RPYn2LyJTK2cYl3XGGGPoW/996C2UCLuKWU 6 | DhNQnN+5geQeh+/2aD2Sul0j1kZn0epFuvMorfyxATkkadrPelSBMBUdmvQv6w2u 7 | MixE1cPC7g/zjjqoOux08hCIpl0CKIukK066PTG4EnPvMacT/MaUUTRQMufH538Q 8 | /NK3O3l6M9qZ7J4eNwlAxtJU5PPk12Y3jQhMHBKzdWR49Xjl1zW+PZ5ua+Wu99Js 9 | ug/STIOV15cL/8O56yVvMRJHeCCKaVJZRufw5hpopXN/t5e4hhltRDhg9Nc+ejhs 10 | lnX1fq/yvLEZFAHz5nAbODcJ4Z0dBLX6VKNKyLzJ1RNR3ODcEX2cgnj0cPdMGFiB 11 | l9+PTHBp6A6ZTQvMNC0KQYt/InSOkRMk87im2KPSXOOPwFc0NLDV499NivsOEQXl 12 | Vj1AdLkiZGm0223m8vpV4Y4F+4t5ctr1+DU+hYvoPCE2BrSctBBx3W4psCIQu00A 13 | c/xlmmwzA4oTTuyWF+pA7ixDwLe7IqvvgJ0LUSDiYx8zu2RnDE5leE10CvthCArq 14 | LKB3mvz0QHTvctG79W3Y6QW/WNvWvrMO5OThP/Xbzo3yO3nwzsImp1x2Pf53lAwz 15 | 6bZUkTNg4FmN+PnGTRe6Sg== 16 | -----END X509 CRL----- 17 | -------------------------------------------------------------------------------- /initializer/fixtures/instance-id/ca.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIE2jCCAsKgAwIBAgIBATANBgkqhkiG9w0BAQsFADANMQswCQYDVQQDEwJjYTAe 3 | Fw0yNTAzMTIxOTEzMThaFw0yNjA5MTIxOTIzMTdaMA0xCzAJBgNVBAMTAmNhMIIC 4 | IjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEApwZxL7ErNkfKIozyaBCh+/8A 5 | 2UimKTgn+oAtOLSxs8O2uv6RB8E8lG23bzvLuvEr2fvtwKIoB+/wedsf3JQISr9+ 6 | pfJTZ7pEYaekKmwYqk7fUWXZJ2PLoHQH4rS8WHHrXVGpD7qEeByT/nOEUXlPfqZi 7 | 0A7iSXGDjOtvhS1oyNu3EA4bmaIlSq7I1m6rgHNgy8SvjPlqYXPOI8bQdw1mmWyW 8 | OFrIiB9SgbB8Rqk/dduwk4DnWghmcQ9bgoBcZkmg4ssObQWOWmjTLFu6mz4n7qFZ 9 | NDWXQ82qUoL+qqPuo/fp0slXAq/M2/lDA3iF9q/XCU9CTQ4GF5ZTBou5WNb96lkj 10 | tUkHn49LdyZwX0cWfnJmcRbAeMgYsAZ8rQaqsu1OybhQmdOTkOAJYy0egxBekDaW 11 | G32tcl+fnuv3aGtfqmzLetB3/HUDK7ZTpctSWMv46ZOVa9T09Ib7d5PXxqHk7aMR 12 | kA8jHhDQsjNYLlgONNx7rxGDCZgftqSv2rlolJEe9cRNhfmdpSk9qrOXQpy6GQBH 13 | MMu5E4OULQWshkD+8mzgSXi0UtrYJ6KMCWvX4fiKAu2Jd3QU2CbJFi2f+lFPAwnV 14 | Hq3XyHu7dO2nKXLqI06vTSkUEvLj67P2lmyGUp1/d4LQNf6zks5x3zWFQgYO0RE4 15 | 5VhliXmxHygCb21k6qcCAwEAAaNFMEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB 16 | /wQIMAYBAf8CAQAwHQYDVR0OBBYEFEW1NttB5issi+R/FGweLN8wN/taMA0GCSqG 17 | SIb3DQEBCwUAA4ICAQARk4nGuxEM4l7DpBubJeWos2wq7DNdjqy5A0nQUale6qsP 18 | szXSwogO1t0Owlu2LinsxK8Wa/Cf2uj7VKA8mwCmowZMHJYku3Ex9IvHwtCpUEt+ 19 | NLWra78DLMdUH4xFG/6q6Jn/9SskzF6UAXDH+Jn65E3ytxDryG8cA8oFGb33iFv1 20 | oHCm89DVNRVEOR7P7HnfWlNcXkJDi8bl4qT6al8tF0OrsGJb6UILyIP1EyRU6maH 21 | mzlOKBwZ37YwuDyNm5JZaxSdgFAB2R3kDydAlNUfY+mk8dY/P1yRDXu7JxT0iHO8 22 | /rFCCW+YLy8J22UhNVslBMX+T5S+kLTsDuW7rCjhSXoWo76BgCi88Vbo2olzF+e3 23 | k+VT6oSATGvlpAmIBoboVBWEpZ7x0opFOCA8FSfVBuKTcqL9E9Rcck2IXJgtFbpE 24 | bXipHkmwYdKUyjHWSzCMrKnTrjDAiLXAjkCHly8mjFYYiA8EMQqLAVVndv7wJSYQ 25 | YZwbG3xIXUXWCbvMnukcYRz2KmKhOHD3vHtdEpsgkZxLAtFK+96cVEdLjP9GjjzL 26 | 6sLmZvdynjWiPjt4MYDbfEkgfQtrN/3VmDOfN0IoQvDOx/EKIDp3684FT5A14412 27 | Puz6mWRWgVvkiI1+PGCtANsxFR2jghUzYnBIIuuuthFcevj3hzTtE62yHuJE+g== 28 | -----END CERTIFICATE----- 29 | -------------------------------------------------------------------------------- /initializer/fixtures/instance-id/ca.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIJKAIBAAKCAgEApwZxL7ErNkfKIozyaBCh+/8A2UimKTgn+oAtOLSxs8O2uv6R 3 | B8E8lG23bzvLuvEr2fvtwKIoB+/wedsf3JQISr9+pfJTZ7pEYaekKmwYqk7fUWXZ 4 | J2PLoHQH4rS8WHHrXVGpD7qEeByT/nOEUXlPfqZi0A7iSXGDjOtvhS1oyNu3EA4b 5 | maIlSq7I1m6rgHNgy8SvjPlqYXPOI8bQdw1mmWyWOFrIiB9SgbB8Rqk/dduwk4Dn 6 | WghmcQ9bgoBcZkmg4ssObQWOWmjTLFu6mz4n7qFZNDWXQ82qUoL+qqPuo/fp0slX 7 | Aq/M2/lDA3iF9q/XCU9CTQ4GF5ZTBou5WNb96lkjtUkHn49LdyZwX0cWfnJmcRbA 8 | eMgYsAZ8rQaqsu1OybhQmdOTkOAJYy0egxBekDaWG32tcl+fnuv3aGtfqmzLetB3 9 | /HUDK7ZTpctSWMv46ZOVa9T09Ib7d5PXxqHk7aMRkA8jHhDQsjNYLlgONNx7rxGD 10 | CZgftqSv2rlolJEe9cRNhfmdpSk9qrOXQpy6GQBHMMu5E4OULQWshkD+8mzgSXi0 11 | UtrYJ6KMCWvX4fiKAu2Jd3QU2CbJFi2f+lFPAwnVHq3XyHu7dO2nKXLqI06vTSkU 12 | EvLj67P2lmyGUp1/d4LQNf6zks5x3zWFQgYO0RE45VhliXmxHygCb21k6qcCAwEA 13 | AQKCAgAnskhEZX83r2hDPex+/zUAh2LUQYf8U/RsfPpCd++kIefUGZyukyaqwEjQ 14 | jw2kqJ0bedzP47pP6J7m10WDT0uJOGoJVsar6IFIFGfYDUjvcT9yQRqTWgyTXgBh 15 | yULaYnjl/PqJWnMRePlTiHDyTDqwhysE+ASgH/J8E5i1tk0pL88aab/1i6wBS/k/ 16 | vZ3VMZbX1y9B+iVmc/eSWTZClVTFMiGh0zHF6Gvblu5yfNcwU75r0D8sDsMKK/Q7 17 | 1/Yd+XHbdRdAoglrQ26tJD/9lZA4DvD8j6Ab5U2NvsR4Ge4l2k4gYunjIZU20s8y 18 | i/qK3s/kzombdrHL+VZSP/MVQkOmhJl1HQPeFmKB+SUAxmIjmWoBVNcxhKlCF6He 19 | u/BGo7OlI3OQGEE+jCekRlWtLWjWc5zCWHau+jrd/4D4+y9SpXVlKXLJH0VCJzdg 20 | bEoKKf6t4BYh3llEn7iSBcO9W+zh0OqSXaGw6jcaMPhtZbC4YHLPjUTjd5wkdHM/ 21 | jBJROwtFdb4sFLsYxsa0Ch7YlawcoLI6DmDyASRQCDTRJ0u9tL6e8O/23dK03m4D 22 | TfEg9tttNQKIJE0X9/NLmma2ag6HZpaAZGzU0UbSuSmgUDOuC4CTEgVg5PFlIJT+ 23 | kEpC7hqCxtjxK/bsbnadTiPwrDMj2a5WTdEpM42Y+PYuMLdLQQKCAQEAxoS73lbX 24 | h24/dlHs14rnLY+hoAK4QWiOIEERConU1OEwuGRlDmvpC6hiYk0/4/rhhkd4+Xdw 25 | fIPtNF67R8r6HuHW6lcT2nJHveT2cCc9FLgKAdbS9gYnuJuD40oJgc+tARBIHMsJ 26 | StmgNiTWLo5yV47hLZx9682bsczW42GfzmeKMvyfXrNqCFDXCb4kCFiSxyZ6oNc2 27 | 7XPmpVcIYwtaiQs1SZ2IcyB4o6BXsythVrFF8gOfI1FDR8F0Qxm+Qwn2SX7ECB58 28 | UkYTZ+b7Br/o44KlQxkm6QggWjoQfEnuEsjXbwb6MdeYQB43bgcm/D+l3Yr13+Px 29 | HtXeNwcNP6NmMwKCAQEA12NAkyvuYxq/Doqgh/QWnmtXs1jMjzBZolJiCUsIGuOG 30 | eapn2tPrdI59V1eU5+st5HQkNKViQAmLreIrCFvKp3PrLrVxk5+5jxaYrjncJIDG 31 | 3twmJJFltMgPENZES/ZCYNkf1zEN3zW3Q4BryMHtoHv9niQRc0NP7V6LaFauEL6D 32 | Fi/eRh7/Rb/QGY/4PlAhbViMFSNVpjHf4DBCXlTPPKUGx6D74S7lR7c0Fr5m/jU8 33 | g+BaX2d46eOtyZ1+cVPiMqG2HMNFF8ef2KVVkyZxp8+4So7s67YGORfrOdqD9epI 34 | v9aDYOi56JtAng34D6nTjdd8Fzd0QC9USxAKXYatvQKCAQEArg++BiJQ0l+ZZ25H 35 | 42nYb3trtLgNxNQfIirK/VmC8rEMnfDxJqb5bI5UzWp8ZbIZQjqy2NGgIJ0wQ+X4 36 | Aef4TVGptklpj/T58IesiQPuq5b+t0QcLzmQZG5/QrAtC9QDFlanVA+2cxnEPxUn 37 | cyTVHu6Zg/ud8T6TkF9R34c+rqTcaP5V4pwfkXEIS3ObdnHrKJEVnqd1cthX2Isq 38 | QGW5GUZpj8V/2aoT/SxfGSslKvU+pggE5dufyW/XN+p/h5pZh3GOAqxwR1dINqcx 39 | XWaxlaJ8swt/sX29mD8nK0NLas8NDj2o7EDkLvwPj/rXdP99uHXaRlg/l9DgCZG2 40 | TSFBPwKCAQAjznU6wi/kO9sNQNCFKXflKDUxNI71MvWDvaxcnSOgzLhbW4/eWiKn 41 | gtSlg4LWt0su0nv+YIwf1zZoVtQOlKvxAJ1Va4aRIxmHBxukwyusydfFztVseNtu 42 | nV+bzfMWqb7JOO9JJ/eFZvmreBrzCgJGDrbP5nEcN1F/RZtpYheX4wQJ2TVbdOW9 43 | I7ElvsBnI40bD4BiNziS43GzZHJ0GidFjq283C9jdRdav8MiEM8wbYs85TxA5gO8 44 | 5kPK46rUjjxpbGbJC1FeLaqOKpY6W0bDvg2GH5KVcPJB5Y8OVBxh8mvbsH6wyp+1 45 | YrHwVKQrfnEUAIG5nlduIDAkNmtytuQFAoIBAGi7IE+FUhqT9cMzjrshhRp1ZF0b 46 | DuhW+dQe4GZ3rTrWQcGeeM2omMr2cMQ3tYi8skJckt+tEVvKR70ggaBPsdqqdjw9 47 | CsHP3Ms3OHYh8Ui6pM8xebvKRuW2hGjD4GmBGfCzi5OCu2CSnRdtz8NxlwWuAJuN 48 | vpKqo6sKizDzwsF4T5r4Gp/u8ClCg1+wVFGZRvaHOB5vuVp+qBNb8/MuHsakWVgV 49 | sh09qlWiUPHkNJx0Nwgq4vbhV7YG06xhWX9+pmxWebeB9PBPGaDHTOLXp73Gh1Mq 50 | mh+iSQy+Eefuwb4z/FOgmQcVrh7HUBBWlqrcsz02pT879AjKQH1mJJZ/KXE= 51 | -----END RSA PRIVATE KEY----- 52 | -------------------------------------------------------------------------------- /initializer/fixtures/instance-id/invalid.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEpAIBAAKCAQEAyCIBMOdKkIk6sig8hiXFfh2Tn/bHtaWgSy2pPS1fI0UhvRj6 3 | RIFE8If/r8dexL8R+1GDN2zDER56DCgjhIiRc+o5kKR/HJmlpZj7f2PTMjmI5bXw 4 | AOMyhPCIs/qcps3tHHlOyu+8/KgSAFxwvkZd0oW0FkF50rivLFY22/SNPQxlC4AU 5 | 7sO1axM19nFKdYZDAWi0QW9gHp/eAu3XIFB3/k1GqaddeGDj/0+L5CPaUpSlnTRF 6 | P2cVaAlBSwrU4ExiTYLrQlcb7UPhOOLgBei87v0nlc1sEPiDcjOelnacHDRaNu/K 7 | 2IMiaSHsdl7lRCgvZEyK1oT4JAxDz+1tx/ubxQIDAQABAoIBABnQ+SJb06yNZzrw 8 | Ic6UNMOuAQsThHOUJ/dKrpgrsCgWlOGVxULtAf2dLYh5SWpL03/95dVSfF9K9Sd4 9 | TgycqVawkjhsX9FKqKmR8G9gazABZ/1p2MnkhPHNLXU6ENcbnUidBWL8Rf65l4jg 10 | Y9LHtPahNLfiPlrGZCJuBKmfBFEpe8BQypHKk6gQFQYk8EbVAlAystinZo+0Kv7u 11 | uN2TE65Gi1p6VsvewxeaZFfWuKcdufHcj696YPQ9sQZ2c4WltI1Vf7KEEevAAfvE 12 | /nnU6q5gGgal5XhMNTRTjd4EHLVruBwHPm/OSZQihX+9+g6ZKRA0kEunfosVHet5 13 | +OIeHAECgYEA30kxHXvHnBXLbrB6uoLsm6QRUE/ap5OfpxOvEIQmaSoWmmbG3biq 14 | 0V5Ns0jXEQNp1z/vh44JPn2YZLT4F+Md52xVhNGKArmFVL3/jKHEeK2cxAnOfLlO 15 | YtfxgqgohU/X4NfISVvlVACu99mL5PX671lWdlBI2ttSREcdmfo2U0UCgYEA5XRo 16 | b9Sy5RvA3yDW0IPKnVXNCGRXJup8lwPI3Z1wF2NRNfNd8nLuPwK2BdcaoBIbsZv/ 17 | G3F4eWM+ndaWtKDYp/e0i6+7tCC6zUoLaTq8JKmz9CYSEbyDBMm3eXQHY9k/igjA 18 | HFCQrsgDtliGZSAcqogoB46o0a8WoRlCCdLEboECgYEAgY1NAwdTnLuEile5Dchz 19 | EicSqJ98hWiA5IbmN1YFl1UFQlbJodHIwqvNt21W45cwbOS6zNLbiDeFGUFrBSkQ 20 | q7rOr76ILeaIds+6m1Us0rwgzhnGhdVapr0WcrGwuRDHd7ybh/zaxW+UFVhS8+jI 21 | zODv6rvQWbOROu5sPW/Q32UCgYEAuOcRseypLM8soaII+Yb6o8ccroKNaKLVO6yl 22 | FVFlnrM+Ike3kUTkkIpSvGoW3p85Ces3rJnIB6neL7tZPr3PWavXJim7DPDDF+Nv 23 | RqE6NCE9DqYPMZPD0PvsikbiHahX95gNl8Okk/RCaZL02lECSLnn6A8iI7cAeVmt 24 | SdU6zgECgYAmxnRHvGCSK1uuJKzGVv+09C8YB33lePjNMoe2e7JrPxnA7GG3Xoue 25 | 3tyq8+uMFvvGk+WnBtq3JPD3gQklHSuJ1WfUwWbIl3zU2d8IfvMxbQYgGFhVueDF 26 | GLK4aAe3Jg1MlAOuHhLH1xV80zmuT1wGAXvq/4WI3dORA8WTwmeuxw== 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /initializer/fixtures/instance-id/invalid.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIC7DCCAdSgAwIBAgIBATANBgkqhkiG9w0BAQsFADAWMRQwEgYDVQQDEwt0ZXN0 3 | Zml4dHVyZTAeFw0xNzAyMDkyMjM0MjlaFw0yNzAyMDkyMjM0MzBaMBYxFDASBgNV 4 | BAMTC3Rlc3RmaXh0dXJlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA 5 | yCIBMOdKkIk6sig8hiXFfh2Tn/bHtaWgSy2pPS1fI0UhvRj6RIFE8If/r8dexL8R 6 | +1GDN2zDER56DCgjhIiRc+o5kKR/HJmlpZj7f2PTMjmI5bXwAOMyhPCIs/qcps3t 7 | HHlOyu+8/KgSAFxwvkZd0oW0FkF50rivLFY22/SNPQxlC4AU7sO1axM19nFKdYZD 8 | AWi0QW9gHp/eAu3XIFB3/k1GqaddeGDj/0+L5CPaUpSlnTRFP2cVaAlBSwrU4Exi 9 | TYLrQlcb7UPhOOLgBei87v0nlc1sEPiDcjOelnacHDRaNu/K2IMiaSHsdl7lRCgv 10 | ZEyK1oT4JAxDz+1tx/ubxQIDAQABo0UwQzAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0T 11 | AQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUXmyV4sTRucUJ2Ywxr2kx19smmKAwDQYJ 12 | KoZIhvcNAQELBQADggEBAJGbTGDI7Cbc5FQ3VdI7UZUJM2/tqLayEySCXnFxFzya 13 | /BkdKH7uzxLuGDz6Tnwn3W6S0XHmItfaccyrU6weqxx/98rYz6OanFbZGEIxzUsc 14 | P8aBI5QmOvaw/fo6KBi/67F/6AVlogPAQcfhgmmz/8C3CadOsDqNlRzS/hzktHMT 15 | l5CAU7ccJ1gJ5BwI+WSIOxnWRN+R8BlV/siVQ5TmcBsOGS2ZbQ5spl3eRUGepC6s 16 | 86Spgmd1ATuj/JkCZO2EL79a8jq4yxSvFHz8KBYYrQmgvueOugO8qLTbX6AdqoNS 17 | x1UZ2iLeYQH71PKHPTq576jjtk+2XP9g9ean38yRIrs= 18 | -----END RSA PRIVATE KEY----- 19 | -------------------------------------------------------------------------------- /initializer/fixtures/instance-id/multiple-ca.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIEHjCCAgagAwIBAgIQSpkwHLZ4Ak9QgPOchqka6TANBgkqhkiG9w0BAQsFADAN 3 | MQswCQYDVQQDEwJjYTAeFw0yNTAzMTIxOTEzMThaFw0yNjA5MTIxOTIzMTZaMBYx 4 | FDASBgNVBAMTC211bHRpcGxlLWNhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB 5 | CgKCAQEAzMbUkURdFL0GVtAdatZ4lWHOXdmEKBDrL96GoWhPxfCZeW9jLoAhxoxb 6 | 0cG/1Vz9FbnXr+2QhHHBh3JcKSA29JqJVnCE6LjNVlGFoYmdLBUCMfgRmpnMrNYu 7 | T4zdyIWmnzFLPz+0RxB2OUIvQpEbKnrYwSbfi7mXCNUvRGKTsozzNrYPPtOVloEj 8 | fYfxVLO1HDeNhMWhw3e4tfjaV/5ZvC6vsGhbVnQ02KLTHDJshb3aIskeVzxCee0Y 9 | BDn5brZdY6wdI3+4PBFRvh/eQutqs9OThVOjEkgEXW/5TGUwAtuw48whvEu+qUjk 10 | n93mYnQcxDfIvfJPC0DZyfg8bTDGqwIDAQABo3EwbzAOBgNVHQ8BAf8EBAMCA7gw 11 | HQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMB0GA1UdDgQWBBQEJ0b/fl9i 12 | iyFI5/nz9SujVYqXzjAfBgNVHSMEGDAWgBRFtTbbQeYrLIvkfxRsHizfMDf7WjAN 13 | BgkqhkiG9w0BAQsFAAOCAgEABvK7CxgL64iYSQGQG/1cV038GvxvUWKl3O2qKz21 14 | 6jqLpLShd9xJel+vhpDBi4Jn6dbjP6nRA48WXK/UiUDLKuYT571edgm4gmBHebrq 15 | V4y5YnJMWf2tg4abrh+Ni0g8jdphX963yON6LRCtRJE0EY1PrMYzZC+IMvoK7vjy 16 | giNIOELLPkyxTNINAytTrHv9zYo1433jY6plwZEn4nIWNYm6JnysPJCKCLmK97W9 17 | 0wLm0ie2ndA8k5Z+7rTSgrDkp4f0Pfp2rk96vG+UHiUzqGg0zrqLgOq9vBCClrbl 18 | DLqXh0v/k04FZc06tx+P0EScMWCv0Urv7irXC0b61AUf73k6pL/XB3AEZlubp6w+ 19 | Dq1pIkNDTQmFSCK0dvFAMvcbLrGtV0ZxHSwY/VwzHgyBKooLGlmurzMyLg8gVbip 20 | o0b2io/ImUAyQScImNnHjQyqWHQlyYk1fkT3vznatrpiE8+RfeVltZe4Dy0S95z2 21 | UPJoEr+XhYuaP1+VdqsTELl9iEtRbzX8hsCkyLOYAvv4j44J156H5ewgB8ZCV5FT 22 | 42empX3mAAbBwAKbDDB/yO8sml+ADAvRIOLlfgniqwO2V9kLFMMYXaQ8sWypuXdl 23 | F/Dg//I4tfrdRXLobFXMK2wpf+dtfbGtwpouXQ1H1hzmrEs8PImhFSq7gq2KzA3v 24 | 2mA= 25 | -----END CERTIFICATE----- 26 | -------------------------------------------------------------------------------- /initializer/fixtures/instance-id/multiple-ca.csr: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE REQUEST----- 2 | MIICWzCCAUMCAQAwFjEUMBIGA1UEAxMLbXVsdGlwbGUtY2EwggEiMA0GCSqGSIb3 3 | DQEBAQUAA4IBDwAwggEKAoIBAQDMxtSRRF0UvQZW0B1q1niVYc5d2YQoEOsv3oah 4 | aE/F8Jl5b2MugCHGjFvRwb/VXP0Vudev7ZCEccGHclwpIDb0molWcITouM1WUYWh 5 | iZ0sFQIx+BGamcys1i5PjN3IhaafMUs/P7RHEHY5Qi9CkRsqetjBJt+LuZcI1S9E 6 | YpOyjPM2tg8+05WWgSN9h/FUs7UcN42ExaHDd7i1+NpX/lm8Lq+waFtWdDTYotMc 7 | MmyFvdoiyR5XPEJ57RgEOflutl1jrB0jf7g8EVG+H95C62qz05OFU6MSSARdb/lM 8 | ZTAC27DjzCG8S76pSOSf3eZidBzEN8i98k8LQNnJ+DxtMMarAgMBAAGgADANBgkq 9 | hkiG9w0BAQsFAAOCAQEABgwf7SEwwZ75jLt9GNtRMGmtAzz4DewqxY/ycRFdzxs8 10 | LSj4vHZhc416v6NCsATH+rOc0dXZmjnngjDshX3L1XRjf1vzzI6ezv+a4J/kVAry 11 | r5Kq3Xp4+ldLDQBXGVVBuagMDVwHW6RO+H57BlS0+cxXhVW+C594y/t7WaegoUFp 12 | 7iuUxF6CqGUbEGzJNIo7bmSRlQyzvoTyi0oYzXz8DXZupwBbrr1tgpB5fgzXy7QL 13 | 9txsk+lB3yj105mwBJTNNpsGSIRF9n8H0KCxiQ11G7wYEtDqPZ3DCoj01yz4IOzK 14 | t/uk6XNs3tEQpHQtV3avbY4hA79EPPkRTvUlADIJvw== 15 | -----END CERTIFICATE REQUEST----- 16 | -------------------------------------------------------------------------------- /initializer/fixtures/instance-id/multiple-ca.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEowIBAAKCAQEAzMbUkURdFL0GVtAdatZ4lWHOXdmEKBDrL96GoWhPxfCZeW9j 3 | LoAhxoxb0cG/1Vz9FbnXr+2QhHHBh3JcKSA29JqJVnCE6LjNVlGFoYmdLBUCMfgR 4 | mpnMrNYuT4zdyIWmnzFLPz+0RxB2OUIvQpEbKnrYwSbfi7mXCNUvRGKTsozzNrYP 5 | PtOVloEjfYfxVLO1HDeNhMWhw3e4tfjaV/5ZvC6vsGhbVnQ02KLTHDJshb3aIske 6 | VzxCee0YBDn5brZdY6wdI3+4PBFRvh/eQutqs9OThVOjEkgEXW/5TGUwAtuw48wh 7 | vEu+qUjkn93mYnQcxDfIvfJPC0DZyfg8bTDGqwIDAQABAoIBAQCvZJoK9pgXPDQi 8 | xUx9Bsfvgv9j6PvF6X/X12xO8W5qZsK9fUdhO8QyMGQwzBeII4ZuRmhUOlFu75RI 9 | dA419266oWaCkAt23Vqa1WZ0zs69RB1GOWiyl4r0etrdrhUEPF1Tur/to53AxHvO 10 | XT7ncCvpfaEMB0Svg722hgpfM2O4KHKjqXOfVSi/4pB+NEGWNls7lAU8s9br1Asp 11 | kcxlcIOXKCQpuuM1GJYuxlFcELlWoUa3jDIZzVJ+98n/z/Le3ww3AnJBoXdduh3r 12 | is1oJpzb5Em3Tsr5AIv+mQKP973n6fW/mJf9LE+3aXplyEAEkcHoLGEQxgDJAuT/ 13 | A0DqjWKJAoGBANTpwMFjUDLwJbByBQdCwLcsrs5aA1B1qYFiMVlVx1TA9AZajg97 14 | oBaQszSeq7111HVSEq+n3NS7KTQd33OpnBimHFrjMgCzcUsJCiTyqDWuKboc99Hx 15 | ud53zfhNxX2wJuKlldPaUKBTVa3CFl0JnbKGpta+6a4UN11RTsCEUP/HAoGBAPY3 16 | jzpAoJF3/iWgFUYjJuq3thf2juAytOVOgxKEmlE0QY49zxwEziWuYzYdYRRyeiHE 17 | JN5rcNSgWWoD3roA1nKOVDk6ShddWO7C33B3olKovZpdIfk75x2983gXFLaEDXOV 18 | vfq1J0ioytvEZ+gAxyvbPQil5FeUkhb5xXtaqgn9AoGAF+/Pw+4ubguhsRyghBh1 19 | IiLb5EcqaDlSPUGU2r5SEq0+whgcMJFthhvuidPs6vf8UtRPVYBBy4jfMQTKwm4n 20 | Jn5GYdF5JasG6bCye0TstFxIRKxNEEVk6CX/+hKESYUsWf7TwWWh+uRjlY1khkE2 21 | gYOx7iK4kuGi99LUT8CQerECgYAnK2uTvthMjCRYZAE+aTU1vggwA79zF14D5Nuh 22 | RIswQ/nx4Q9jy7fn8rhB0aayFAwt9wBOihUnHmNbJEZ4nM2A5/eqKwXCdc1CHqph 23 | QAcI02NmfU58UfVQm/lxr2pSJuvk6XuRuOQJASFUmQhWtlj5NyWcjJeo/y/Gi/HI 24 | 0AGhGQKBgCns5+0Bc6pAqhDCTnA12tcW8u+vMnq7itVvY+obDTUK0NcKDB/Y9imh 25 | dBjvraZm013O/Ow5ENXGzquujFfsgXW7230inLrE894qGj0r1FVTiaqABwWVtw0K 26 | qWEl/WOw7ZfODIn4uDd4/l6n9sTnV4hz/chmni4SWcSn0RiQNQcu 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /initializer/fixtures/instance-id/non-pem.crt: -------------------------------------------------------------------------------- 1 | invalid certificate 2 | -------------------------------------------------------------------------------- /initializer/fixtures/instance-id/non-pem.key: -------------------------------------------------------------------------------- 1 | invalid private key 2 | -------------------------------------------------------------------------------- /initializer/fixtures/regenerate-certs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | this_dir="$(cd $(dirname $0) && pwd)" 6 | 7 | pushd "$this_dir" 8 | 9 | rm -rf out 10 | certstrap init --common-name "ca" --passphrase "" 11 | certstrap request-cert --common-name "multiple-ca" --passphrase "" 12 | certstrap sign multiple-ca --CA "ca" 13 | 14 | mv -f out/* ./instance-id/ 15 | rm -rf out 16 | 17 | certstrap init --common-name "ca" --passphrase "" 18 | certstrap request-cert --common-name "client" --passphrase "" 19 | certstrap sign client --CA "ca" 20 | 21 | mv -f out/* ./downloader/ 22 | rm -rf out 23 | 24 | certstrap init --common-name "extra-ca" --passphrase "" 25 | 26 | mv -f out/* ./systemcerts/ 27 | rm -rf out 28 | 29 | popd 30 | -------------------------------------------------------------------------------- /initializer/fixtures/systemcerts/extra-ca.crl: -------------------------------------------------------------------------------- 1 | -----BEGIN X509 CRL----- 2 | MIICgjBsAgEBMA0GCSqGSIb3DQEBCwUAMBMxETAPBgNVBAMTCGV4dHJhLWNhFw0y 3 | NTAzMTIxOTIzMjBaFw0yNjA5MTIxOTIzMjBaMACgIzAhMB8GA1UdIwQYMBaAFKXL 4 | V6MpQb3sJLnpquJ7IXdotuBWMA0GCSqGSIb3DQEBCwUAA4ICAQAdLQJePs8BvAiv 5 | B0thKk2mlJaSjo6GRy+kOBuPNAxifTF/l9WndU9tX8MjkFF/hkPwQtLsVnveGQkt 6 | GO3nWtjRXesfVOrMC8ahsFtRSX1QQpIciwI1J7/zioqN7F5jeLjN40Y8+NE+7Y2W 7 | fe+yJ+8Bk0EvGnEhhue7jqRes1E9OQdTMlEjzmGRVyxzpI/Wiq7S40OZjTf6r2sP 8 | Hn8+2JSXhG/hgadb+/QL6lNjxXS5gVqkiwLZ+ncm2xGiNjPQr1+ejDMXiReL7jeN 9 | z1XejcawgOIPH/Va1a+fPpmsOGeg1R6XwlCzEuiRy9URCWMYf7Q/zPjhnz650YKF 10 | vQEizyE9whclmQ1AwQWl87cfRdS7YgrhpZKJ/o17a/+tDWM19SeeZTnyMjntJxhI 11 | lNFmYeMtSFoZyRLB5/Ld5KBQLijoEUGHzrxLXoNEj1RLM3bGj2fa8ln3K3SzEP7Q 12 | hXBk6JO4PnUMgk5NWhQzQsuVMB3zQLYcKDLVdMtII6i2v6b9Ca8UHKcqDBVjom3T 13 | X8Fxf6SpkT4ccRTMB4INvqehVvpSlf9FiuTqBopMDabHXNYyLEs2h9u7BE4rp+Cz 14 | 7jE2Xu4dwsS/CF/I4lnUZFYE+2CncfswP/Dv2DTKsSATdnnnz8D+Pcfj5VKelSe0 15 | 661c6o/HjDnYDtzEIUiDKYBOFnxvWA== 16 | -----END X509 CRL----- 17 | -------------------------------------------------------------------------------- /initializer/fixtures/systemcerts/extra-ca.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIE5jCCAs6gAwIBAgIBATANBgkqhkiG9w0BAQsFADATMREwDwYDVQQDEwhleHRy 3 | YS1jYTAeFw0yNTAzMTIxOTEzMjBaFw0yNjA5MTIxOTIzMjBaMBMxETAPBgNVBAMT 4 | CGV4dHJhLWNhMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAq7qOzqJE 5 | o2FGOAFrCjg+bceTcC8kyvkw55++p6pZMFKKCXFHARYsqhsX5H1zOh3tN8FlMH+k 6 | Bn8wPQnSkUe+v5hcnxYu/EOygxvO341STg9SxxHsNUhvwZpzzdYVrZ0sXED5mEk3 7 | 51SPobjLCwYD+GkJngtwgMGyMeGgboteddnxhPvhuJrtVJ8MNUykRU2Uc15LRGxs 8 | QLiJ2joZlpfEhgtmDOJVbCOrTTkQlT5CmIXSPl9bAS4v8ub1+BIBc9qq7JPwM/Be 9 | TDYpo/naOHaaiFxphaBE6CB2ik7erb22LKSRJItr8wvRjxRB7vFQZqdUXeDR9QY/ 10 | Zl51qeT/Bg0SU3n7+D6AC1dUQukhd8K5Y2WTb808hvyxmHG4dCunSDlRjgGHanxb 11 | Jt0Ep+trG0UzeeVNZi0kRZ5aj93euP7doQwZVT4Y+xD6pc+gZuRnfd4ogmpCXiYa 12 | 394NZA2vmzBJBEpd3Y3HpU9/x4T3jfL/mbd8KESXVf6LFbE0LSlh9kf/nENus+IU 13 | Y+vfksBK3kKDIMCJxqM6S4+SPgF780Wtx0W2v3TkPFwWu9DwjvYp5UXjXtPA1Iig 14 | 6H2CQEg8UILU6R8TcFle/0dU8aRnagnMlhYNFXZ3P8/TurL55MU9O5dHKxHO7r3y 15 | 0uI9g+76ai6sDcG1F+EtMVqplSqlxgLk5wMCAwEAAaNFMEMwDgYDVR0PAQH/BAQD 16 | AgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFKXLV6MpQb3sJLnpquJ7 17 | IXdotuBWMA0GCSqGSIb3DQEBCwUAA4ICAQCTkIp3fds6JuXuP7lbWKHo7x1VqFQe 18 | BX4Zub+NvUni4YuKTojftqqIZHRh0nTOJv5rV0N+jfgHuJldqQeJn6D78LaWfsyw 19 | CrCsPWgI0SJ4KyR8fqqHJGR0ezyXuQMxfEPQsO9ih/MWSnJy8wCeDoIQXjG9FrJ/ 20 | xZZPqLetS2Eg9C7Y1fgYy/S4M0vH+6pwZvelonNKMPBCn+VmWx1AOYLSFM/RIjn6 21 | pXLX0rsuXbTKQneN+yZpAjGgUFxudq/gvy9Q4T1pelphNcSiDTAGlK35DTmgUAE9 22 | hZZZwqBCaK9KLi03mip4d3BmgQmVKToRaSeTYhUjBSohQT1nr7LI9S8iNKtg4Ifz 23 | RSDnK6KgPe2goiVQgxjoDH4D2cagUIGZGKf4AKxcyWmtCmCOQGHtsmcroBbfkF7X 24 | e1ew/tbteTwk/jXAmtmQ14nFpyEfRVIRX3VsNClV30g5iAgJeJPHsW58PdakOdN8 25 | uF34CB+vS9SZMlrBvPt6ntppyE4bdknGkAmVoZeqW7exZ8qKUmEBtY+hbXRNwILK 26 | eQpMElxW/oSho/o5xX84hKJyJdGQGD6SasQxjPZ8k/EhGVVOeuACoT2DR/bCePwP 27 | 2UcW088lzm+zUJVKlKd4WYOD0RdowPoweqlLnNji/4qNJWdb7shDW1qXNyIToj3e 28 | BXkpkvv7OypgPg== 29 | -----END CERTIFICATE----- 30 | -------------------------------------------------------------------------------- /initializer/fixtures/systemcerts/extra-ca.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | 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 51 | -----END RSA PRIVATE KEY----- 52 | -------------------------------------------------------------------------------- /initializer/initializer_suite_test.go: -------------------------------------------------------------------------------- 1 | package initializer_test 2 | 3 | import ( 4 | . "github.com/onsi/ginkgo/v2" 5 | . "github.com/onsi/gomega" 6 | 7 | "testing" 8 | ) 9 | 10 | func TestInitializer(t *testing.T) { 11 | RegisterFailHandler(Fail) 12 | RunSpecs(t, "Initializer Suite") 13 | } 14 | -------------------------------------------------------------------------------- /initializer/package.go: -------------------------------------------------------------------------------- 1 | package initializer // import "code.cloudfoundry.org/executor/initializer" 2 | -------------------------------------------------------------------------------- /package.go: -------------------------------------------------------------------------------- 1 | package executor // import "code.cloudfoundry.org/executor" 2 | -------------------------------------------------------------------------------- /resource_converters.go: -------------------------------------------------------------------------------- 1 | package executor 2 | 3 | import "code.cloudfoundry.org/bbs/models" 4 | 5 | func EnvironmentVariablesToModel(envVars []EnvironmentVariable) []models.EnvironmentVariable { 6 | out := make([]models.EnvironmentVariable, len(envVars)) 7 | for i, val := range envVars { 8 | out[i].Name = val.Name 9 | out[i].Value = val.Value 10 | } 11 | return out 12 | } 13 | 14 | func EnvironmentVariablesFromModel(envVars []*models.EnvironmentVariable) []EnvironmentVariable { 15 | out := make([]EnvironmentVariable, len(envVars)) 16 | for i, val := range envVars { 17 | out[i].Name = val.Name 18 | out[i].Value = val.Value 19 | } 20 | return out 21 | } 22 | 23 | func VolumeMountedFilesFromModel(envFiles []*models.File) []VolumeMountedFiles { 24 | out := make([]VolumeMountedFiles, len(envFiles)) 25 | for i, envFile := range envFiles { 26 | out[i].Path = envFile.Path 27 | out[i].Content = envFile.Content 28 | } 29 | 30 | return out 31 | } 32 | -------------------------------------------------------------------------------- /resources_test.go: -------------------------------------------------------------------------------- 1 | package executor_test 2 | 3 | import ( 4 | "strings" 5 | 6 | . "github.com/onsi/ginkgo/v2" 7 | . "github.com/onsi/gomega" 8 | 9 | "code.cloudfoundry.org/executor" 10 | ) 11 | 12 | var _ = Describe("Container", func() { 13 | Describe("HasTags", func() { 14 | var container executor.Container 15 | 16 | Context("when tags are nil", func() { 17 | BeforeEach(func() { 18 | container = executor.Container{ 19 | Tags: nil, 20 | } 21 | }) 22 | 23 | It("returns true if requested tags are nil", func() { 24 | Expect(container.HasTags(nil)).To(BeTrue()) 25 | }) 26 | 27 | It("returns false if requested tags are not nil", func() { 28 | Expect(container.HasTags(executor.Tags{"a": "b"})).To(BeFalse()) 29 | }) 30 | }) 31 | 32 | Context("when tags are not nil", func() { 33 | BeforeEach(func() { 34 | container = executor.Container{ 35 | Tags: executor.Tags{"a": "b"}, 36 | } 37 | }) 38 | 39 | It("returns true when found", func() { 40 | Expect(container.HasTags(executor.Tags{"a": "b"})).To(BeTrue()) 41 | }) 42 | 43 | It("returns false when nil", func() { 44 | Expect(container.HasTags(nil)).To(BeFalse()) 45 | }) 46 | 47 | It("returns false when not found", func() { 48 | Expect(container.HasTags(executor.Tags{"a": "c"})).To(BeFalse()) 49 | }) 50 | }) 51 | }) 52 | 53 | Describe("Subtract", func() { 54 | const ( 55 | defaultDiskMB = 20 56 | defaultMemoryMB = 30 57 | defaultContainers = 3 58 | ) 59 | 60 | It("returns false when the number of containers is less than 1", func() { 61 | resources := executor.NewExecutorResources(defaultMemoryMB, defaultDiskMB, 0) 62 | resourceToSubtract := executor.NewResource(defaultMemoryMB-1, defaultDiskMB-1, -1) 63 | Expect(resources.Subtract(&resourceToSubtract)).To(BeFalse()) 64 | }) 65 | 66 | It("returns false when disk size exceeds total available disk size", func() { 67 | resources := executor.NewExecutorResources(defaultMemoryMB, 10, defaultContainers) 68 | resourceToSubtract := executor.NewResource(defaultMemoryMB-1, 20, -1) 69 | Expect(resources.Subtract(&resourceToSubtract)).To(BeFalse()) 70 | }) 71 | 72 | It("returns false when memory exceeds total available memory", func() { 73 | resources := executor.NewExecutorResources(10, defaultDiskMB, defaultContainers) 74 | resourceToSubtract := executor.NewResource(20, defaultDiskMB-1, -1) 75 | Expect(resources.Subtract(&resourceToSubtract)).To(BeFalse()) 76 | }) 77 | }) 78 | 79 | Describe("TransitionToComplete", func() { 80 | var ( 81 | container *executor.Container 82 | failureReason string 83 | ) 84 | 85 | BeforeEach(func() { 86 | container = &executor.Container{} 87 | failureReason = "foo" 88 | }) 89 | 90 | JustBeforeEach(func() { 91 | container.TransitionToComplete(true, failureReason, false) 92 | }) 93 | 94 | It("does not truncate short failure reasons", func() { 95 | Expect(container.RunResult.FailureReason).To(Equal("foo")) 96 | }) 97 | 98 | When("failure reason is longer than 10000 characters", func() { 99 | BeforeEach(func() { 100 | failureReason = strings.Repeat("a", 6000) + strings.Repeat("b", 6000) 101 | }) 102 | 103 | It("is truncated", func() { 104 | Expect(container.RunResult.FailureReason).To(HaveLen(10000)) 105 | Expect(container.RunResult.FailureReason[4991:5008]).To(Equal("\n... (truncated)\n")) 106 | }) 107 | }) 108 | }) 109 | }) 110 | --------------------------------------------------------------------------------