Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Opsgenie plugin implementation #6154

Merged
merged 35 commits into from
Nov 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
0332b5f
feat: Opsgenie plugin implementation
sandesvitor Sep 26, 2023
83758b9
fix(lint): lint with gofmt
sandesvitor Sep 27, 2023
9fb9d35
refactor(lint): removing unused config-ui files
sandesvitor Sep 27, 2023
1b17cf0
feat(task): changed incident collector to accept incremental collection
sandesvitor Sep 30, 2023
3065bfa
fix(config-ui): adjust the params for bp add connection (#6241)
mintsweet Oct 13, 2023
dff0a6f
refactor: removed unused code (#6243)
klesh Oct 13, 2023
067e89a
refactor(config-ui): remove content about user info (#6245)
mintsweet Oct 16, 2023
82b0422
fix(azure): fix 400 error when cloing azure repos (#6246)
d4x1 Oct 16, 2023
af225fc
fix: normalize_bp_settings throws error (#6249)
klesh Oct 16, 2023
efc05df
fix: pg ci (#6252)
klesh Oct 16, 2023
5effb0c
fix(gitlab): fix incremental deployment collector (#6254)
d4x1 Oct 16, 2023
7468e1a
fix: modify _tool_jira_issue_relationships primary key (#6253)
abeizn Oct 16, 2023
8c33afb
feat(pagerduty): search remote scope by keyword (#6255)
d4x1 Oct 16, 2023
5c0e767
refactor(impl): refactoring impl.go and service model
sandesvitor Oct 16, 2023
fe4294f
refactor(comment): removing comment from incident collector
sandesvitor Oct 16, 2023
2c408a3
feat(task): added GetCreated function
sandesvitor Oct 16, 2023
fc44e53
feat(zentao): check db url when testing connections (#6258)
d4x1 Oct 17, 2023
fb89d7d
fix(configui): tagsLimit should be a number (#6261)
d4x1 Oct 17, 2023
a3fdb2c
fix(check): fixing lint in config-ui
sandesvitor Oct 17, 2023
cc0d362
Merge branch 'main' into feat-opsgenie-plugin
sandesvitor Oct 19, 2023
92f143d
refactor(newline): adding removed newline
sandesvitor Oct 19, 2023
bc8e1da
Merge branch 'main' into feat-opsgenie-plugin
d4x1 Oct 20, 2023
11d0644
fix(config-ui): removed old plugin type
sandesvitor Oct 20, 2023
b471516
Merge branch 'feat-opsgenie-plugin' of github.com:sandesvitor/incubat…
sandesvitor Oct 20, 2023
afdcf08
Merge branch 'main' into feat-opsgenie-plugin
sandesvitor Oct 20, 2023
77e1f71
Merge branch 'main' into feat-opsgenie-plugin
sandesvitor Oct 23, 2023
edd727f
Merge branch 'main' into feat-opsgenie-plugin
sandesvitor Oct 24, 2023
ddf11d2
Merge branch 'main' into feat-opsgenie-plugin
sandesvitor Oct 26, 2023
7adbe60
refactor(config-ui): remove type inheritance from opsgenieconfig
sandesvitor Oct 26, 2023
f00e4f9
Merge branch 'main' into feat-opsgenie-plugin
sandesvitor Oct 30, 2023
2454632
Merge branch 'main' into feat-opsgenie-plugin
d4x1 Nov 8, 2023
4e87f73
Merge branch 'main' into feat-opsgenie-plugin
sandesvitor Nov 10, 2023
94af888
style(config-ui): update icon with icon.svg
sandesvitor Nov 10, 2023
2950f6b
Merge branch 'main' into feat-opsgenie-plugin
sandesvitor Nov 10, 2023
bad3490
Merge branch 'feat-opsgenie-plugin' of github.com:sandesvitor/incubat…
sandesvitor Nov 10, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
119 changes: 119 additions & 0 deletions backend/plugins/opsgenie/api/blueprint_v200.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
/*
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package api

import (
"github.com/apache/incubator-devlake/core/errors"
coreModels "github.com/apache/incubator-devlake/core/models"
"github.com/apache/incubator-devlake/core/models/domainlayer"
"github.com/apache/incubator-devlake/core/models/domainlayer/didgen"
"github.com/apache/incubator-devlake/core/models/domainlayer/ticket"
"github.com/apache/incubator-devlake/core/plugin"
"github.com/apache/incubator-devlake/core/utils"
"github.com/apache/incubator-devlake/helpers/pluginhelper/api"
"github.com/apache/incubator-devlake/plugins/opsgenie/models"
"github.com/apache/incubator-devlake/plugins/opsgenie/tasks"
)

func MakeDataSourcePipelinePlanV200(
subtaskMetas []plugin.SubTaskMeta,
connectionId uint64,
bpScopes []*coreModels.BlueprintScope,
) (coreModels.PipelinePlan, []plugin.Scope, errors.Error) {
// get the connection info for url
connection := &models.OpsgenieConnection{}
err := connectionHelper.FirstById(connection, connectionId)
if err != nil {
return nil, nil, err
}

plan := make(coreModels.PipelinePlan, len(bpScopes))
plan, err = makeDataSourcePipelinePlanV200(subtaskMetas, plan, bpScopes, connection)
if err != nil {
return nil, nil, err
}
scopes, err := makeScopesV200(bpScopes, connection)
if err != nil {
return nil, nil, err
}

return plan, scopes, nil
}

func makeDataSourcePipelinePlanV200(
subtaskMetas []plugin.SubTaskMeta,
plan coreModels.PipelinePlan,
bpScopes []*coreModels.BlueprintScope,
connection *models.OpsgenieConnection,
) (coreModels.PipelinePlan, errors.Error) {
for i, bpScope := range bpScopes {
// get board and scope config from db
service, scopeConfig, err := scopeHelper.DbHelper().GetScopeAndConfig(connection.ID, bpScope.ScopeId)
if err != nil {
return nil, err
}
// construct task options for opsgenie
op := &tasks.OpsgenieOptions{
ConnectionId: service.ConnectionId,
ServiceId: service.Id,
ServiceName: service.Name,
}

var options map[string]any
options, err = tasks.EncodeTaskOptions(op)
if err != nil {
return nil, err
}
var subtasks []string
subtasks, err = api.MakePipelinePlanSubtasks(subtaskMetas, scopeConfig.Entities)
if err != nil {
return nil, err
}
stage := []*coreModels.PipelineTask{
{
Plugin: "opsgenie",
Subtasks: subtasks,
Options: options,
},
}
plan[i] = stage
}
return plan, nil
}

func makeScopesV200(bpScopes []*coreModels.BlueprintScope, connection *models.OpsgenieConnection) ([]plugin.Scope, errors.Error) {
scopes := make([]plugin.Scope, 0)
for _, bpScope := range bpScopes {
// get board and scope config from db
service, scopeConfig, err := scopeHelper.DbHelper().GetScopeAndConfig(connection.ID, bpScope.ScopeId)
if err != nil {
return nil, err
}
// add board to scopes
if utils.StringsContains(scopeConfig.Entities, plugin.DOMAIN_TYPE_TICKET) {
scopeTicket := &ticket.Board{
DomainEntity: domainlayer.DomainEntity{
Id: didgen.NewDomainIdGenerator(&models.Service{}).Generate(connection.ID, service.Id),
},
Name: service.Name,
}
scopes = append(scopes, scopeTicket)
}
}
return scopes, nil
}
153 changes: 153 additions & 0 deletions backend/plugins/opsgenie/api/connection.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
/*
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package api

import (
"context"
"net/http"

"github.com/apache/incubator-devlake/core/errors"
"github.com/apache/incubator-devlake/core/plugin"
"github.com/apache/incubator-devlake/helpers/pluginhelper/api"
"github.com/apache/incubator-devlake/plugins/opsgenie/models"
)

// @Summary test opsgenie connection
// @Description Test Opsgenie Connection
// @Tags plugins/opsgenie
// @Param body body models.OpsgenieConn true "json body"
// @Success 200 {object} shared.ApiBody "Success"
// @Failure 400 {string} errcode.Error "Bad Request"
// @Failure 500 {string} errcode.Error "Internal Error"
// @Router /plugins/opsgenie/test [POST]
func TestConnection(input *plugin.ApiResourceInput) (*plugin.ApiResourceOutput, errors.Error) {
var connection models.OpsgenieConn

err := api.Decode(input.Body, &connection, vld)
if err != nil {
return nil, err
}

apiClient, err := api.NewApiClientFromConnection(context.TODO(), basicRes, &connection)
if err != nil {
return nil, err
}

// check API permissions
response, err := apiClient.Get("v2/heartbeats/HeartbeatName/ping", nil, nil)
if err != nil {
return nil, err
}

if response.StatusCode == http.StatusUnauthorized {
return nil, errors.HttpStatus(http.StatusUnauthorized).New("StatusUnauthorized error when testing api or read_api permissions")
}

if response.StatusCode == http.StatusUnprocessableEntity {
return nil, errors.HttpStatus(http.StatusUnprocessableEntity).New("StatusUnprocessableEntity error when testing api")
}

if response.StatusCode == http.StatusForbidden {
return nil, errors.HttpStatus(http.StatusForbidden).New("API Key need 'Read' and 'Configuration access' Access rights")
}

if response.StatusCode == http.StatusOK {
return &plugin.ApiResourceOutput{Body: nil, Status: http.StatusOK}, nil
}

return &plugin.ApiResourceOutput{Body: nil, Status: response.StatusCode}, errors.HttpStatus(response.StatusCode).Wrap(err, "could not validate connection")
}

// @Summary create opsgenie connection
// @Description Create Opsgenie connection
// @Tags plugins/opsgenie
// @Param body body models.OpsgenieConnection true "json body"
// @Success 200 {object} models.OpsgenieConnection
// @Failure 400 {string} errcode.Error "Bad Request"
// @Failure 500 {string} errcode.Error "Internal Error"
// @Router /plugins/opsgenie/connections [POST]
func PostConnections(input *plugin.ApiResourceInput) (*plugin.ApiResourceOutput, errors.Error) {
connection := &models.OpsgenieConnection{}
err := connectionHelper.Create(connection, input)
if err != nil {
return nil, err
}
return &plugin.ApiResourceOutput{Body: connection, Status: http.StatusOK}, nil
}

// @Summary patch opsgenie connection
// @Description Patch Opsgenie connection
// @Tags plugins/opsgenie
// @Param body body models.OpsgenieConnection true "json body"
// @Success 200 {object} models.OpsgenieConnection
// @Failure 400 {string} errcode.Error "Bad Request"
// @Failure 500 {string} errcode.Error "Internal Error"
// @Router /plugins/opsgenie/connections/{connectionId} [PATCH]
func PatchConnection(input *plugin.ApiResourceInput) (*plugin.ApiResourceOutput, errors.Error) {
connection := &models.OpsgenieConnection{}
err := connectionHelper.Patch(connection, input)
if err != nil {
return nil, err
}
return &plugin.ApiResourceOutput{Body: connection, Status: http.StatusOK}, nil
}

// @Summary delete opsgenie connection
// @Description Delete Opsgenie connection
// @Tags plugins/opsgenie
// @Success 200 {object} models.OpsgenieConnection
// @Failure 400 {string} errcode.Error "Bad Request"
// @Failure 409 {object} services.BlueprintProjectPairs "References exist to this connection"
// @Failure 500 {string} errcode.Error "Internal Error"
// @Router /plugins/opsgenie/connections/{connectionId} [DELETE]
func DeleteConnection(input *plugin.ApiResourceInput) (*plugin.ApiResourceOutput, errors.Error) {
return connectionHelper.Delete(&models.OpsgenieConnection{}, input)
}

// @Summary list opsgenie connections
// @Description List Opsgenie connections
// @Tags plugins/opsgenie
// @Success 200 {object} models.OpsgenieConnection
// @Failure 400 {string} errcode.Error "Bad Request"
// @Failure 500 {string} errcode.Error "Internal Error"
// @Router /plugins/opsgenie/connections [GET]
func ListConnections(input *plugin.ApiResourceInput) (*plugin.ApiResourceOutput, errors.Error) {
var connections []models.OpsgenieConnection
err := connectionHelper.List(&connections)
if err != nil {
return nil, err
}

return &plugin.ApiResourceOutput{Body: connections}, nil
}

// @Summary get opsgenie connection
// @Description Get Opsgenie connection
// @Tags plugins/opsgenie
// @Success 200 {object} models.OpsgenieConnection
// @Failure 400 {string} errcode.Error "Bad Request"
// @Failure 500 {string} errcode.Error "Internal Error"
// @Router /plugins/opsgenie/connections/{connectionId} [GET]
func GetConnection(input *plugin.ApiResourceInput) (*plugin.ApiResourceOutput, errors.Error) {
connection := &models.OpsgenieConnection{}
err := connectionHelper.First(connection, input.Params)
if err != nil {
return nil, err
}
return &plugin.ApiResourceOutput{Body: connection}, nil
}
59 changes: 59 additions & 0 deletions backend/plugins/opsgenie/api/init.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package api

import (
"github.com/apache/incubator-devlake/core/context"
"github.com/apache/incubator-devlake/core/plugin"
"github.com/apache/incubator-devlake/helpers/pluginhelper/api"
"github.com/apache/incubator-devlake/plugins/opsgenie/models"
"github.com/go-playground/validator/v10"
)

var vld *validator.Validate
var connectionHelper *api.ConnectionApiHelper

var scopeHelper *api.ScopeApiHelper[models.OpsgenieConnection, models.Service, models.OpsenieScopeConfig]

var basicRes context.BasicRes

func Init(br context.BasicRes, p plugin.PluginMeta) {

basicRes = br
vld = validator.New()
connectionHelper = api.NewConnectionHelper(
basicRes,
vld,
p.Name(),
)
params := &api.ReflectionParameters{
ScopeIdFieldName: "Id",
ScopeIdColumnName: "id",
RawScopeParamName: "ScopeId",
SearchScopeParamName: "name",
}
scopeHelper = api.NewScopeHelper[models.OpsgenieConnection, models.Service, models.OpsenieScopeConfig](
basicRes,
vld,
connectionHelper,
api.NewScopeDatabaseHelperImpl[models.OpsgenieConnection, models.Service, models.OpsenieScopeConfig](
basicRes, connectionHelper, params),
params,
&api.ScopeHelperOptions{},
)
}
Loading