blob: 298964913f2d10f88606cf0b886c19e3ed03be58 [file] [log] [blame]
package staticdnsentry
/*
* 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.
*/
import (
"errors"
"fmt"
"net/http"
"strconv"
"time"
"github.com/apache/trafficcontrol/lib/go-tc"
"github.com/apache/trafficcontrol/lib/go-tc/tovalidate"
"github.com/apache/trafficcontrol/lib/go-util"
"github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/api"
"github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/dbhelpers"
validation "github.com/go-ozzo/ozzo-validation"
"github.com/go-ozzo/ozzo-validation/is"
)
type TOStaticDNSEntry struct {
api.APIInfoImpl `json:"-"`
tc.StaticDNSEntryNullable
}
func (v *TOStaticDNSEntry) GetLastUpdated() (*time.Time, bool, error) {
return api.GetLastUpdated(v.APIInfo().Tx, *v.ID, "staticdnsentry")
}
func (v *TOStaticDNSEntry) SetLastUpdated(t tc.TimeNoMod) { v.LastUpdated = &t }
func (v *TOStaticDNSEntry) InsertQuery() string { return insertQuery() }
func (v *TOStaticDNSEntry) NewReadObj() interface{} { return &tc.StaticDNSEntryNullable{} }
func (v *TOStaticDNSEntry) SelectQuery() string { return selectQuery() }
func (v *TOStaticDNSEntry) ParamColumns() map[string]dbhelpers.WhereColumnInfo {
return map[string]dbhelpers.WhereColumnInfo{
"address": dbhelpers.WhereColumnInfo{Column: "sde.address"},
"cachegroup": dbhelpers.WhereColumnInfo{Column: "cg.name"},
"cachegroupId": dbhelpers.WhereColumnInfo{Column: "cg.id"},
"deliveryservice": dbhelpers.WhereColumnInfo{Column: "ds.xml_id"},
"deliveryserviceId": dbhelpers.WhereColumnInfo{Column: "sde.deliveryservice"},
"host": dbhelpers.WhereColumnInfo{Column: "sde.host"},
"id": dbhelpers.WhereColumnInfo{Column: "sde.id"},
"ttl": dbhelpers.WhereColumnInfo{Column: "sde.ttl"},
"type": dbhelpers.WhereColumnInfo{Column: "tp.name"},
"typeId": dbhelpers.WhereColumnInfo{Column: "tp.id"},
}
}
func (v *TOStaticDNSEntry) UpdateQuery() string { return updateQuery() }
func (v *TOStaticDNSEntry) DeleteQuery() string { return deleteQuery() }
func (staticDNSEntry TOStaticDNSEntry) GetKeyFieldsInfo() []api.KeyFieldInfo {
return []api.KeyFieldInfo{{Field: "id", Func: api.GetIntKey}}
}
//Implementation of the Identifier, Validator interface functions
func (staticDNSEntry TOStaticDNSEntry) GetKeys() (map[string]interface{}, bool) {
if staticDNSEntry.ID == nil {
return map[string]interface{}{"id": 0}, false
}
return map[string]interface{}{"id": *staticDNSEntry.ID}, true
}
func (staticDNSEntry TOStaticDNSEntry) GetAuditName() string {
if staticDNSEntry.Host != nil {
return *staticDNSEntry.Host
}
if staticDNSEntry.ID != nil {
return strconv.Itoa(*staticDNSEntry.ID)
}
return "0"
}
func (staticDNSEntry TOStaticDNSEntry) GetType() string { return "staticDNSEntry" }
func (staticDNSEntry *TOStaticDNSEntry) SetKeys(keys map[string]interface{}) {
i, _ := keys["id"].(int) //this utilizes the non panicking type assertion, if the thrown away ok variable is false i will be the zero of the type, 0 here.
staticDNSEntry.ID = &i
}
// Validate fulfills the api.Validator interface.
func (staticDNSEntry TOStaticDNSEntry) Validate() (error, error) {
typeStr, err := tc.ValidateTypeID(staticDNSEntry.ReqInfo.Tx.Tx, &staticDNSEntry.TypeID, "staticdnsentry")
if err != nil {
return err, nil
}
var addressErr, ttlErr error
switch typeStr {
case "A_RECORD":
addressErr = validation.Validate(staticDNSEntry.Address, validation.Required, is.IPv4)
case "AAAA_RECORD":
addressErr = validation.Validate(staticDNSEntry.Address, validation.Required, is.IPv6)
case "CNAME_RECORD":
addressErr = validation.Validate(staticDNSEntry.Address, validation.Required, is.DNSName)
address := *staticDNSEntry.Address
if addressErr == nil {
lastChar := address[len(address)-1:]
if lastChar != "." {
addressErr = fmt.Errorf("for type: CNAME_RECORD must have a trailing period")
}
}
default:
addressErr = validation.Validate(staticDNSEntry.Address, validation.Required)
}
if staticDNSEntry.TTL != nil {
if *staticDNSEntry.TTL == 0 {
ttlErr = validation.Validate(staticDNSEntry.TTL, is.Digit)
}
} else {
ttlErr = validation.Validate(staticDNSEntry.TTL, validation.Required)
}
errs := validation.Errors{
"host": validation.Validate(staticDNSEntry.Host, validation.Required, is.DNSName),
"address": addressErr,
"deliveryserviceId": validation.Validate(staticDNSEntry.DeliveryServiceID, validation.Required),
"ttl": ttlErr,
"typeId": validation.Validate(staticDNSEntry.TypeID, validation.Required),
}
return util.JoinErrs(tovalidate.ToErrors(errs)), nil
}
func (en *TOStaticDNSEntry) Read(h http.Header, useIMS bool) ([]interface{}, error, error, int, *time.Time) {
api.DefaultSort(en.APIInfo(), "host")
return api.GenericRead(h, en, useIMS)
}
func (en *TOStaticDNSEntry) Create() (error, error, int) {
var cdnName tc.CDNName
var err error
if en.DeliveryServiceID != nil {
_, cdnName, _, err = dbhelpers.GetDSNameAndCDNFromID(en.ReqInfo.Tx.Tx, *en.DeliveryServiceID)
if err != nil {
return nil, err, http.StatusInternalServerError
}
userErr, sysErr, errCode := dbhelpers.CheckIfCurrentUserCanModifyCDN(en.ReqInfo.Tx.Tx, string(cdnName), en.ReqInfo.User.UserName)
if userErr != nil || sysErr != nil {
return userErr, sysErr, errCode
}
}
return api.GenericCreate(en)
}
func (en *TOStaticDNSEntry) Update(h http.Header) (error, error, int) {
var cdnName tc.CDNName
var err error
if en.DeliveryServiceID != nil {
_, cdnName, _, err = dbhelpers.GetDSNameAndCDNFromID(en.ReqInfo.Tx.Tx, *en.DeliveryServiceID)
if err != nil {
return nil, err, http.StatusInternalServerError
}
userErr, sysErr, errCode := dbhelpers.CheckIfCurrentUserCanModifyCDN(en.ReqInfo.Tx.Tx, string(cdnName), en.ReqInfo.User.UserName)
if userErr != nil || sysErr != nil {
return userErr, sysErr, errCode
}
}
return api.GenericUpdate(h, en)
}
func (en *TOStaticDNSEntry) Delete() (error, error, int) {
var cdnName tc.CDNName
var err error
var dsID int
if en.DeliveryServiceID != nil {
dsID = *en.DeliveryServiceID
} else if en.ID != nil {
dsID, err = dbhelpers.GetDSIDFromStaticDNSEntry(en.ReqInfo.Tx.Tx, *en.ID)
if err != nil {
return nil, errors.New("couldn't get DS ID from static dns entry ID: " + err.Error()), http.StatusInternalServerError
}
}
_, cdnName, _, err = dbhelpers.GetDSNameAndCDNFromID(en.ReqInfo.Tx.Tx, dsID)
if err != nil {
return nil, err, http.StatusInternalServerError
}
userErr, sysErr, errCode := dbhelpers.CheckIfCurrentUserCanModifyCDN(en.ReqInfo.Tx.Tx, string(cdnName), en.ReqInfo.User.UserName)
if userErr != nil || sysErr != nil {
return userErr, sysErr, errCode
}
return api.GenericDelete(en)
}
func (v *TOStaticDNSEntry) SelectMaxLastUpdatedQuery(where, orderBy, pagination, tableName string) string {
return `SELECT max(t) from (
SELECT max(sde.last_updated) as t FROM staticdnsentry as sde
JOIN type as tp on sde.type = tp.id
LEFT JOIN cachegroup as cg ON sde.cachegroup = cg.id
JOIN deliveryservice as ds on sde.deliveryservice = ds.id ` + where + orderBy + pagination +
` UNION ALL
select max(last_updated) as t from last_deleted l where l.table_name='staticdnsentry') as res`
}
func insertQuery() string {
query := `INSERT INTO staticdnsentry (
address,
deliveryservice,
cachegroup,
host,
type,
ttl) VALUES (
:address,
:deliveryservice_id,
:cachegroup_id,
:host,
:type_id,
:ttl) RETURNING id,last_updated`
return query
}
func updateQuery() string {
query := `UPDATE
staticdnsentry SET
id=:id,
address=:address,
deliveryservice=:deliveryservice_id,
cachegroup=:cachegroup_id,
host=:host,
type=:type_id,
ttl=:ttl
WHERE id=:id RETURNING last_updated`
return query
}
func selectQuery() string {
return `SELECT
ds.xml_id as dsname,
sde.host,
sde.id as id,
sde.deliveryservice as deliveryservice_id,
sde.ttl,
sde.address,
sde.last_updated,
tp.id as type_id,
tp.name as type,
cg.id as cachegroup_id,
cg.name as cachegroup
FROM staticdnsentry as sde
JOIN type as tp on sde.type = tp.id
LEFT JOIN cachegroup as cg ON sde.cachegroup = cg.id
JOIN deliveryservice as ds on sde.deliveryservice = ds.id
`
}
func deleteQuery() string {
query := `DELETE FROM staticdnsentry
WHERE id=:id`
return query
}