aboutsummaryrefslogtreecommitdiffstats
path: root/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/stubs/LoggingDeploymentIssues.java
blob: 6015da037630a494ccfd622bbf7f7245d526e5c4 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

package com.yahoo.vespa.hosted.controller.api.integration.stubs;

import com.yahoo.component.annotation.Inject;
import com.yahoo.component.Version;
import com.yahoo.config.provision.ApplicationId;
import com.yahoo.vespa.hosted.controller.api.integration.organization.AccountId;
import com.yahoo.vespa.hosted.controller.api.integration.organization.Contact;
import com.yahoo.vespa.hosted.controller.api.integration.organization.DeploymentIssues;
import com.yahoo.vespa.hosted.controller.api.integration.organization.IssueId;
import com.yahoo.vespa.hosted.controller.api.integration.organization.User;

import java.time.Clock;
import java.time.Duration;
import java.time.Instant;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
import java.util.logging.Logger;

/**
 * A memory backed implementation of the Issues API which logs changes and does nothing else.
 * 
 * @author bratseth
 * @author jonmv
 */
public class LoggingDeploymentIssues implements DeploymentIssues {

    private static final Logger log = Logger.getLogger(LoggingDeploymentIssues.class.getName());
    
    /** Whether the platform is currently broken. */
    protected final AtomicBoolean platformIssue = new AtomicBoolean(false);
    /** Last updates for each issue -- used to determine if issues are already logged and when to escalate. */
    protected final Map<IssueId, Instant> issueUpdates = new HashMap<>();

    /** Used to fabricate unique issue ids. */
    private final AtomicLong issueIdSequence = new AtomicLong(0);

    private final Clock clock;

    @SuppressWarnings("unused") // Created by dependency injection.
    @Inject
    public LoggingDeploymentIssues() {
        this(Clock.systemUTC());
    }

    protected LoggingDeploymentIssues(Clock clock) {
        this.clock = clock;
    }

    @Override
    public IssueId fileUnlessOpen(Optional<IssueId> issueId, ApplicationId applicationId, AccountId assigneeId, User assignee, Contact contact) {
        return fileUnlessPresent(issueId, applicationId);
    }

    @Override
    public IssueId fileUnlessOpen(Collection<ApplicationId> applicationIds, Version version) {
        if ( ! platformIssue.get())
            log.info("These applications are all failing deployment to version " + version + ":\n" + applicationIds);

        platformIssue.set(true);
        return null;
    }

    @Override
    public void escalateIfInactive(IssueId issueId, Duration maxInactivity, Optional<Contact> contact) {
        if (issueUpdates.containsKey(issueId) && issueUpdates.get(issueId).isBefore(clock.instant().minus(maxInactivity)))
            escalateIssue(issueId);
    }

    protected void escalateIssue(IssueId issueId) {
        issueUpdates.put(issueId, clock.instant());
        log.info("Deployment issue " + issueId + " should be escalated.");
    }

    protected IssueId fileIssue(ApplicationId applicationId) {
        IssueId issueId = IssueId.from("" + issueIdSequence.incrementAndGet());
        issueUpdates.put(issueId, clock.instant());
        log.info("Deployment issue " + issueId  +": " + applicationId + " has failing deployments.");
        return issueId;
    }

    private IssueId fileUnlessPresent(Optional<IssueId> issueId, ApplicationId applicationId) {
        platformIssue.set(false);
        return issueId.filter(issueUpdates::containsKey).orElseGet(() -> fileIssue(applicationId));
    }

}