diff --git a/scripts/selinux/nginx_agent.pp b/scripts/selinux/nginx_agent.pp index 529b1745d..6834be7e8 100644 Binary files a/scripts/selinux/nginx_agent.pp and b/scripts/selinux/nginx_agent.pp differ diff --git a/scripts/selinux/nginx_agent.te b/scripts/selinux/nginx_agent.te index 940de10c8..541111474 100644 --- a/scripts/selinux/nginx_agent.te +++ b/scripts/selinux/nginx_agent.te @@ -9,20 +9,13 @@ type nginx_agent_t; type nginx_agent_exec_t; init_daemon_domain(nginx_agent_t, nginx_agent_exec_t) -# permissive nginx_agent_t; +permissive nginx_agent_t; type nginx_agent_log_t; logging_log_file(nginx_agent_log_t) -### New -type nginx_agent_config_t; -files_config_file(nginx_agent_config_t) - -type nginx_agent_var_run_t; -files_pid_file(nginx_agent_var_run_t) - -type nginx_agent_port_t; -corenet_port(nginx_agent_port_t) +type nginx_agent_unit_file_t; +systemd_unit_file(nginx_agent_unit_file_t) ######################################## # @@ -35,7 +28,6 @@ manage_dirs_pattern(nginx_agent_t, nginx_agent_log_t, nginx_agent_log_t) manage_files_pattern(nginx_agent_t, nginx_agent_log_t, nginx_agent_log_t) manage_lnk_files_pattern(nginx_agent_t, nginx_agent_log_t, nginx_agent_log_t) logging_log_filetrans(nginx_agent_t, nginx_agent_log_t, { dir file lnk_file }) -logging_write_generic_logs(nginx_agent_t, nginx_agent_log_t, nginx_agent_log_t) domain_use_interactive_fds(nginx_agent_t) @@ -44,407 +36,140 @@ files_read_etc_files(nginx_agent_t) miscfiles_read_localization(nginx_agent_t) require { - type net_conf_t; - type init_t; - type node_t; - type bin_t; - type sysctl_net_t; - type http_port_t; - type unreserved_port_t; - type httpd_exec_t; - type shell_exec_t; - type httpd_config_t; - type httpd_t; - type system_cronjob_t; - type setroubleshootd_t; - type proc_t; type unconfined_t; + type var_run_t; type rpcbind_t; - type auditd_t; - type sysfs_t; - type unconfined_service_t; - type system_dbusd_t; - type tuned_t; - type irqbalance_t; - type passwd_file_t; - type dhcpc_t; - type proc_net_t; - type httpd_sys_content_t; - type kernel_t; - type fs_t; - type syslogd_t; - type udev_t; - type systemd_logind_t; - type chronyd_t; - type audisp_t; + type system_cronjob_t; type policykit_t; - type gssproxy_t; + type irqbalance_t; + type tuned_t; type postfix_pickup_t; - type sshd_t; - type crond_t; - type getty_t; - type lvm_t; + type dhcpc_t; + type system_dbusd_t; type postfix_qmgr_t; - type postfix_master_t; - type admin_home_t; - type httpd_var_run_t; - type NetworkManager_t; - type rhnsd_t; - class capability { sys_ptrace net_bind_service }; - class dir { getattr read search }; - class filesystem getattr; - class tcp_socket { accept bind connect create getattr getopt listen name_bind name_connect node_bind setopt }; - class lnk_file { getattr read }; - class file { execute execute_no_trans getattr open read write }; - class udp_socket { connect create getattr setopt }; - class netlink_route_socket { bind create getattr nlmsg_read }; + type nginx_agent_t; + class sock_file { create setattr unlink }; + class netlink_route_socket { bind create getattr nlmsg_read }; + class capability sys_ptrace; + class dir { getattr search }; + class file { getattr open read }; } #============= nginx_agent_t ============== -allow nginx_agent_t audisp_t:dir { getattr search }; -allow nginx_agent_t audisp_t:file { getattr open read }; -allow nginx_agent_t auditd_t:dir { getattr search }; -allow nginx_agent_t auditd_t:file { getattr open read }; -allow nginx_agent_t chronyd_t:dir { getattr search }; -allow nginx_agent_t chronyd_t:file { getattr open read }; -allow nginx_agent_t crond_t:dir { getattr search }; +allow nginx_agent_t dhcpc_t:dir { getattr search }; allow nginx_agent_t dhcpc_t:file { getattr open read }; -allow nginx_agent_t fs_t:filesystem getattr; -allow nginx_agent_t getty_t:file { getattr open read }; -allow nginx_agent_t gssproxy_t:dir { getattr search }; -allow nginx_agent_t gssproxy_t:file { getattr open read }; -allow nginx_agent_t httpd_config_t:dir { getattr open read }; -allow nginx_agent_t httpd_exec_t:file getattr; -allow nginx_agent_t httpd_t:file { getattr open read }; allow nginx_agent_t irqbalance_t:dir { getattr search }; allow nginx_agent_t irqbalance_t:file { getattr open read }; -allow nginx_agent_t kernel_t:file { getattr open read }; -allow nginx_agent_t lvm_t:dir { getattr search }; -allow nginx_agent_t lvm_t:file { getattr open read }; -allow nginx_agent_t passwd_file_t:file { open read }; allow nginx_agent_t policykit_t:dir { getattr search }; allow nginx_agent_t policykit_t:file { getattr open read }; -allow nginx_agent_t postfix_master_t:file { getattr open read }; allow nginx_agent_t postfix_pickup_t:dir { getattr search }; +allow nginx_agent_t postfix_pickup_t:file { getattr open read }; allow nginx_agent_t postfix_qmgr_t:dir { getattr search }; -allow nginx_agent_t proc_net_t:file { getattr open read }; -allow nginx_agent_t proc_t:dir read; -allow nginx_agent_t proc_t:file { getattr open read }; +allow nginx_agent_t postfix_qmgr_t:file { getattr open read }; allow nginx_agent_t rpcbind_t:dir { getattr search }; allow nginx_agent_t rpcbind_t:file { getattr open read }; +allow nginx_agent_t self:capability sys_ptrace; allow nginx_agent_t self:netlink_route_socket { bind create getattr nlmsg_read }; -allow nginx_agent_t setroubleshootd_t:dir { getattr search }; -allow nginx_agent_t shell_exec_t:file execute; -allow nginx_agent_t sshd_t:dir { getattr search }; -allow nginx_agent_t sysfs_t:lnk_file read; -allow nginx_agent_t syslogd_t:file { getattr open read }; allow nginx_agent_t system_cronjob_t:dir { getattr search }; allow nginx_agent_t system_cronjob_t:file { getattr open read }; allow nginx_agent_t system_dbusd_t:dir { getattr search }; allow nginx_agent_t system_dbusd_t:file { getattr open read }; -allow nginx_agent_t systemd_logind_t:dir { getattr search }; -allow nginx_agent_t systemd_logind_t:file { getattr open read }; +allow nginx_agent_t tuned_t:dir { getattr search }; allow nginx_agent_t tuned_t:file { getattr open read }; -allow nginx_agent_t udev_t:file { getattr open read }; -allow nginx_agent_t unconfined_service_t:dir { getattr search }; -allow nginx_agent_t unconfined_service_t:file { getattr open read }; allow nginx_agent_t unconfined_t:dir { getattr search }; -allow nginx_agent_t dhcpc_t:dir { getattr search }; -allow nginx_agent_t getty_t:dir { getattr search }; -allow nginx_agent_t httpd_sys_content_t:dir read; -allow nginx_agent_t kernel_t:dir { getattr search }; -allow nginx_agent_t passwd_file_t:file read; -allow nginx_agent_t postfix_master_t:dir { getattr search }; -allow nginx_agent_t proc_net_t:file read; -allow nginx_agent_t self:capability sys_ptrace; -allow nginx_agent_t syslogd_t:dir { getattr search }; -allow nginx_agent_t tuned_t:dir { getattr search }; -allow nginx_agent_t udev_t:dir { getattr search }; -allow nginx_agent_t bin_t:file { execute execute_no_trans }; -allow nginx_agent_t crond_t:file { getattr open read }; -allow nginx_agent_t http_port_t:tcp_socket name_connect; -allow nginx_agent_t httpd_config_t:file { getattr open read }; -allow nginx_agent_t httpd_config_t:lnk_file getattr; -allow nginx_agent_t httpd_exec_t:file { execute execute_no_trans open read }; -allow nginx_agent_t httpd_sys_content_t:file { getattr open read }; -allow nginx_agent_t httpd_t:dir { getattr search }; -allow nginx_agent_t httpd_t:lnk_file read; -allow nginx_agent_t init_t:file { getattr open read }; -allow nginx_agent_t net_conf_t:file { getattr open read }; -allow nginx_agent_t node_t:tcp_socket node_bind; -allow nginx_agent_t postfix_pickup_t:file { getattr open read }; -allow nginx_agent_t postfix_qmgr_t:file { getattr open read }; -allow nginx_agent_t self:tcp_socket { accept bind connect create getattr getopt listen setopt }; -allow nginx_agent_t self:udp_socket { connect create getattr setopt }; -allow nginx_agent_t setroubleshootd_t:file { getattr open read }; -allow nginx_agent_t sshd_t:file { getattr open read }; -allow nginx_agent_t sysctl_net_t:dir search; -allow nginx_agent_t sysctl_net_t:file { open read }; -allow nginx_agent_t sysfs_t:dir read; -allow nginx_agent_t sysfs_t:file { getattr open read }; -allow nginx_agent_t sysfs_t:lnk_file getattr; allow nginx_agent_t unconfined_t:file { getattr open read }; -allow nginx_agent_t unreserved_port_t:tcp_socket name_bind; -allow nginx_agent_t crond_t:file { getattr open read }; -allow nginx_agent_t nginx_agent_config_t:dir { search list_dir_perms }; -allow nginx_agent_t nginx_agent_config_t:file { getattr open read read_file_perms }; -allow nginx_agent_t nginx_agent_config_t:lnk_file read_lnk_file_perms; -allow nginx_agent_t NetworkManager_t:dir { getattr search }; -allow nginx_agent_t NetworkManager_t:file { getattr open read }; -allow nginx_agent_t http_port_t:tcp_socket name_bind; -allow nginx_agent_t httpd_var_run_t:file write; -allow nginx_agent_t passwd_file_t:file getattr; -allow nginx_agent_t rhnsd_t:dir { getattr search }; -allow nginx_agent_t rhnsd_t:file { getattr open read }; -allow nginx_agent_t self:capability net_bind_service; -manage_dirs_pattern(nginx_agent_t, nginx_agent_var_run_t, nginx_agent_var_run_t) -manage_files_pattern(nginx_agent_t, nginx_agent_var_run_t, nginx_agent_var_run_t) -manage_lnk_files_pattern(nginx_agent_t, nginx_agent_var_run_t, nginx_agent_var_run_t) -manage_sock_files_pattern(nginx_agent_t, nginx_agent_var_run_t, nginx_agent_var_run_t) -files_pid_filetrans(nginx_agent_t, nginx_agent_var_run_t, { dir file }) -allow nginx_agent_t httpd_config_t:dir search; -allow nginx_agent_t unreserved_port_t:tcp_socket name_connect; -allow nginx_agent_t nginx_agent_exec_t:file execmod; -allow nginx_agent_t self:process execmem; -allow nginx_agent_t self:netlink_route_socket { bind create getattr nlmsg_read read write }; -allow nginx_agent_t self:process signal; -allow nginx_agent_t self:tcp_socket { connect create getattr getopt read setopt write }; -allow nginx_agent_t self:capability { dac_override dac_read_search }; -allow nginx_agent_t user_home_t:file { open read }; -allow nginx_agent_t sysfs_t:file { open read }; -allow nginx_agent_t nginx_agent_port_t:tcp_socket name_connect; -allow nginx_agent_t admin_home_t:file { getattr open read }; -allow nginx_agent_t httpd_config_t:dir { add_name remove_name write }; -allow nginx_agent_t httpd_config_t:file { create unlink write }; -allow nginx_agent_t httpd_t:process signal; -allow nginx_agent_t tmp_t:dir { add_name write }; -allow nginx_agent_t tmp_t:file { create write }; -files_manage_var_dirs(nginx_agent_t) -files_rw_var_files(nginx_agent_t) -miscfiles_read_generic_certs(nginx_agent_t) -corenet_tcp_bind_generic_node(nginx_agent_t) -corenet_tcp_connect_all_ports(nginx_agent_t) -apache_exec(nginx_agent_t) -apache_read_config(nginx_agent_t) -apache_read_log(nginx_agent_t) -apache_read_pid_files(nginx_agent_t) -apache_systemctl(nginx_agent_t) -corecmd_exec_bin(nginx_agent_t) -dbus_read_lib_files(nginx_agent_t) -kernel_read_system_state(nginx_agent_t) -sysnet_read_config(nginx_agent_t) -userdom_mmap_user_home_content_files(nginx_agent_t) - -require { - type nginx_agent_t; - type rhsmcertd_t; - type unconfined_t; - type var_run_t; - class dir { getattr search }; - class lnk_file read; - class sock_file { getattr setattr unlink }; -} - -#============= nginx_agent_t ============== -allow nginx_agent_t rhsmcertd_t:dir { getattr search }; -allow nginx_agent_t unconfined_t:lnk_file read; -allow nginx_agent_t var_run_t:sock_file { getattr setattr unlink }; +allow nginx_agent_t var_run_t:sock_file { create setattr unlink }; +chronyd_systemctl(nginx_agent_t) +corecmd_exec_ls(nginx_agent_t) +cron_read_state_crond(nginx_agent_t) +dev_list_sysfs(nginx_agent_t) +dev_read_sysfs(nginx_agent_t) +files_manage_generic_tmp_files(nginx_agent_t) +files_read_var_lib_files(nginx_agent_t) +files_rw_pid_dirs(nginx_agent_t) +fs_getattr_xattr_fs(nginx_agent_t) getty_systemctl(nginx_agent_t) -sssd_search_lib(nginx_agent_t) -sssd_systemctl(nginx_agent_t) +gssproxy_systemctl(nginx_agent_t) +init_read_state(nginx_agent_t) +kernel_getattr_proc(nginx_agent_t) +kernel_list_proc(nginx_agent_t) +kernel_read_net_sysctls(nginx_agent_t) +kernel_read_network_state(nginx_agent_t) +kernel_read_state(nginx_agent_t) +kernel_read_system_state(nginx_agent_t) +kernel_search_network_sysctl(nginx_agent_t) +logging_systemctl_audit(nginx_agent_t) +postfix_read_master_state(nginx_agent_t) +ssh_systemctl(nginx_agent_t) +systemd_logind_read_state(nginx_agent_t) +udev_read_state(nginx_agent_t) require { + type policykit_t; + type dhcpc_t; + type rpcbind_t; type nginx_agent_t; - type rhsmcertd_t; - type unconfined_t; - type var_run_t; class dir { getattr search }; - class file read; - class lnk_file read; - class sock_file create; -} - -#============= nginx_agent_t ============== - -#!!!! This avc is allowed in the current policy -allow nginx_agent_t rhsmcertd_t:dir { getattr search }; -allow nginx_agent_t rhsmcertd_t:file read; - -#!!!! This avc is allowed in the current policy -allow nginx_agent_t unconfined_t:lnk_file read; -allow nginx_agent_t var_run_t:sock_file create; -getty_systemctl(nginx_agent_t) -sssd_read_public_files(nginx_agent_t) -sssd_search_lib(nginx_agent_t) -sssd_stream_connect(nginx_agent_t) -sssd_systemctl(nginx_agent_t) -userdom_list_user_home_dirs(nginx_agent_t) - -require { - type nginx_agent_t; - type rhsmcertd_t; - class file { open read }; + class file { getattr open read }; } #============= nginx_agent_t ============== #!!!! This avc is allowed in the current policy -allow nginx_agent_t rhsmcertd_t:file read; -allow nginx_agent_t rhsmcertd_t:file open; -sssd_read_public_files(nginx_agent_t) -sssd_stream_connect(nginx_agent_t) -userdom_list_user_home_dirs(nginx_agent_t) - -require { - type nginx_agent_t; - type rhsmcertd_t; - class file { getattr open }; -} - -#============= nginx_agent_t ============== +allow nginx_agent_t dhcpc_t:dir { getattr search }; #!!!! This avc is allowed in the current policy -allow nginx_agent_t rhsmcertd_t:file open; -allow nginx_agent_t rhsmcertd_t:file getattr; - -require { - type nginx_agent_t; - type rhsmcertd_t; - class file getattr; -} - -#============= nginx_agent_t ============== +allow nginx_agent_t policykit_t:file { getattr open read }; #!!!! This avc is allowed in the current policy -allow nginx_agent_t rhsmcertd_t:file getattr; - -require { - type nginx_agent_config_t; - type nginx_agent_t; - class file write; -} - -#============= nginx_agent_t ============== -allow nginx_agent_t nginx_agent_config_t:file write; +allow nginx_agent_t rpcbind_t:file { getattr open read }; +kernel_read_network_state(nginx_agent_t) require { + type unconfined_t; + type httpd_var_run_t; + type http_port_t; type nginx_agent_t; - type rpm_t; + type netutils_t; + class capability { dac_override net_bind_service }; + class tcp_socket { bind connect create getattr getopt name_bind name_connect setopt }; + class lnk_file read; class dir { getattr search }; + class file { getattr open read write }; } #============= nginx_agent_t ============== -allow nginx_agent_t rpm_t:dir { getattr search }; +allow nginx_agent_t http_port_t:tcp_socket { name_bind name_connect }; +allow nginx_agent_t httpd_var_run_t:file { open read write }; +allow nginx_agent_t netutils_t:dir { getattr search }; +allow nginx_agent_t netutils_t:file { getattr open read }; +allow nginx_agent_t self:capability { dac_override net_bind_service }; +allow nginx_agent_t self:tcp_socket { bind connect create getattr getopt setopt }; +allow nginx_agent_t unconfined_t:lnk_file read; +apache_exec(nginx_agent_t) +apache_manage_config(nginx_agent_t) +apache_read_config(nginx_agent_t) +apache_read_log(nginx_agent_t) +apache_signal(nginx_agent_t) +apache_systemctl(nginx_agent_t) +auth_read_passwd(nginx_agent_t) +corenet_tcp_bind_generic_node(nginx_agent_t) +files_manage_urandom_seed(nginx_agent_t) +miscfiles_read_certs(nginx_agent_t) require { type sshd_net_t; - type nginx_agent_t; - class dir { getattr search }; + type rpm_script_t; + type mandb_t; } -#============= nginx_agent_t ============== +allow nginx_agent_t mandb_t:dir { getattr search }; +allow nginx_agent_t mandb_t:file { getattr open read }; +allow nginx_agent_t rpm_script_t:dir { getattr search }; +allow nginx_agent_t rpm_script_t:file { getattr open read }; allow nginx_agent_t sshd_net_t:dir { getattr search }; +allow nginx_agent_t sshd_net_t:file { getattr open read }; -require { - type nginx_agent_t; - type sshd_net_t; - class file read; -} - -#============= nginx_agent_t ============== -allow nginx_agent_t sshd_net_t:file read; - -require { - type sshd_net_t; - type nginx_agent_t; - class file open; -} - -#============= nginx_agent_t ============== -allow nginx_agent_t sshd_net_t:file open; - -require { - type sshd_net_t; - type nginx_agent_t; - class file getattr; -} - -#============= nginx_agent_t ============== -allow nginx_agent_t sshd_net_t:file getattr; - -require { - type rpm_t; - type nginx_agent_t; - class file read; -} - -#============= nginx_agent_t ============== -allow nginx_agent_t rpm_t:file read; - -require { - type nginx_agent_t; -} - -#============= nginx_agent_t ============== apache_list_cache(nginx_agent_t) -rng_systemctl_rngd(nginx_agent_t) -userdom_manage_user_home_content_dirs(nginx_agent_t) - -require { - type rpm_t; - type nginx_agent_t; - class file open; -} - -#============= nginx_agent_t ============== -allow nginx_agent_t rpm_t:file open; -corenet_tcp_bind_http_cache_port(nginx_agent_t) -rng_systemctl_rngd(nginx_agent_t) -userdom_manage_user_home_content_dirs(nginx_agent_t) - -require { - type nginx_agent_t; -} - -#============= nginx_agent_t ============== -files_rw_etc_files(nginx_agent_t) - -require { - type nginx_agent_t; -} - -#============= nginx_agent_t ============== -files_read_var_lib_files(nginx_agent_t) - -require { - type nginx_agent_t; -} - -#============= nginx_agent_t ============== -files_manage_usr_files(nginx_agent_t) -files_read_var_lib_files(nginx_agent_t) - -require { - type nginx_agent_t; -} - -#============= nginx_agent_t ============== -apache_manage_lib(nginx_agent_t) - -require { - type nginx_agent_t; -} - -#============= nginx_agent_t ============== -files_manage_mounttab(nginx_agent_t) - -require { - type nginx_agent_t; -} - -#============= nginx_agent_t ============== -apache_manage_config(nginx_agent_t) fs_getattr_dos_fs(nginx_agent_t) -kernel_read_network_state_symlinks(nginx_agent_t) -files_read_generic_tmp_files(nginx_agent_t) - +init_read_script_state(nginx_agent_t) diff --git a/sdk/config_helpers.go b/sdk/config_helpers.go index eccc5b749..8ad40b98c 100644 --- a/sdk/config_helpers.go +++ b/sdk/config_helpers.go @@ -10,8 +10,10 @@ package sdk import ( "crypto/sha256" "encoding/hex" + "encoding/json" "errors" "fmt" + "io" "io/fs" "net" "net/http" @@ -669,41 +671,46 @@ func AddAuxfileToNginxConfig( func parseAddressesFromServerDirective(parent *crossplane.Directive) []string { addresses := []string{} + hosts := []string{} port := "80" for _, dir := range parent.Block { - address := "127.0.0.1" + hostname := "127.0.0.1" switch dir.Directive { case "listen": host, listenPort, err := net.SplitHostPort(dir.Args[0]) if err == nil { if host == "*" || host == "" { - address = "127.0.0.1" + hostname = "127.0.0.1" } else if host == "::" || host == "::1" { - address = "[::1]" + hostname = "[::1]" } else { - address = host + hostname = host } port = listenPort } else { if isPort(dir.Args[0]) { port = dir.Args[0] } else { - address = dir.Args[0] + hostname = dir.Args[0] } } - addresses = append(addresses, fmt.Sprintf("%s:%s", address, port)) + hosts = append(hosts, hostname) case "server_name": if dir.Args[0] == "_" { // default server continue } - address = dir.Args[0] - addresses = append(addresses, fmt.Sprintf("%s:%s", address, port)) + hostname = dir.Args[0] + hosts = append(hosts, hostname) } } + for _, host := range hosts { + addresses = append(addresses, fmt.Sprintf("%s:%s", host, port)) + } + return addresses } @@ -729,7 +736,7 @@ func statusAPICallback(parent *crossplane.Directive, current *crossplane.Directi plusUrls := getUrlsForLocationDirective(parent, current, plusAPIDirective) for _, url := range plusUrls { - if pingStatusAPIEndpoint(url) { + if pingNginxPlusApiEndpoint(url) { log.Debugf("api at %q found", url) return url } @@ -737,7 +744,7 @@ func statusAPICallback(parent *crossplane.Directive, current *crossplane.Directi } for _, url := range ossUrls { - if pingStatusAPIEndpoint(url) { + if pingStubStatusApiEndpoint(url) { log.Debugf("stub_status at %q found", url) return url } @@ -747,16 +754,6 @@ func statusAPICallback(parent *crossplane.Directive, current *crossplane.Directi return "" } -// pingStatusAPIEndpoint ensures the statusAPI is reachable from the agent -func pingStatusAPIEndpoint(statusAPI string) bool { - client := http.Client{Timeout: 50 * time.Millisecond} - - if _, err := client.Head(statusAPI); err != nil { - return false - } - return true -} - // Deprecated: use either GetStubStatusApiUrl or GetNginxPlusApiUrl func GetStatusApiInfoWithIgnoreDirectives(confFile string, ignoreDirectives []string) (statusApi string, err error) { payload, err := crossplane.Parse(confFile, @@ -834,7 +831,7 @@ func stubStatusApiCallback(parent *crossplane.Directive, current *crossplane.Dir urls := getUrlsForLocationDirective(parent, current, stubStatusAPIDirective) for _, url := range urls { - if pingStatusAPIEndpoint(url) { + if pingStubStatusApiEndpoint(url) { log.Debugf("stub_status at %q found", url) return url } @@ -848,7 +845,7 @@ func nginxPlusApiCallback(parent *crossplane.Directive, current *crossplane.Dire urls := getUrlsForLocationDirective(parent, current, plusAPIDirective) for _, url := range urls { - if pingStatusAPIEndpoint(url) { + if pingNginxPlusApiEndpoint(url) { log.Debugf("plus API at %q found", url) return url } @@ -858,6 +855,56 @@ func nginxPlusApiCallback(parent *crossplane.Directive, current *crossplane.Dire return "" } +func pingStubStatusApiEndpoint(statusAPI string) bool { + client := http.Client{Timeout: 50 * time.Millisecond} + resp, err := client.Get(statusAPI) + if err != nil { + return false + } + + if resp.StatusCode != 200 { + return false + } + + bodyBytes, err := io.ReadAll(resp.Body) + if err != nil { + return false + } + + // Expecting API to return data like this: + // + // Active connections: 2 + // server accepts handled requests + // 18 18 3266 + // Reading: 0 Writing: 1 Waiting: 1 + body := string(bodyBytes) + return strings.Contains(body, "Active connections") && strings.Contains(body, "server accepts handled requests") +} + +func pingNginxPlusApiEndpoint(statusAPI string) bool { + client := http.Client{Timeout: 50 * time.Millisecond} + resp, err := client.Get(statusAPI) + if err != nil { + return false + } + + if resp.StatusCode != 200 { + return false + } + + bodyBytes, err := io.ReadAll(resp.Body) + if err != nil { + return false + } + + // Expecting API to return the api versions in an array of positive integers + // subset example: [ ... 6,7,8,9 ...] + var responseBody []int + err = json.Unmarshal(bodyBytes, &responseBody) + + return err == nil +} + func getUrlsForLocationDirective(parent *crossplane.Directive, current *crossplane.Directive, locationDirectiveName string) []string { var urls []string // process from the location block diff --git a/sdk/config_helpers_test.go b/sdk/config_helpers_test.go index 234107949..25436583a 100644 --- a/sdk/config_helpers_test.go +++ b/sdk/config_helpers_test.go @@ -779,12 +779,16 @@ func TestGetStatusApiInfo(t *testing.T) { server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { if req.URL.String() == "/privateapi" { - data := []byte("api OK") + data := []byte("[1,2,3,4,5,6,7,8]") _, err := rw.Write(data) assert.Nil(t, err) } else if req.URL.String() == "/stub_status" { - rw.WriteHeader(http.StatusInternalServerError) - data := []byte("stub_status OK") + data := []byte(` +Active connections: 2 +server accepts handled requests + 18 18 3266 +Reading: 0 Writing: 1 Waiting: 1 + `) _, err := rw.Write(data) assert.Nil(t, err) } @@ -1164,6 +1168,22 @@ server { allow 127.0.0.1; deny all; } +} + `, + }, + { + plus: []string{ + "http://127.0.0.1:49151/api", + "http://127.0.0.1:49151/api", + }, + conf: ` +server { + server_name 127.0.0.1; + listen 127.0.0.1:49151; + access_log off; + location /api { + api; + } } `, }, @@ -1784,3 +1804,106 @@ func TestGetAppProtectPolicyAndSecurityLogFiles(t *testing.T) { }) } } + +func TestPingNginxPlusApiEndpoint(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { + if req.URL.String() == "/good_api" { + data := []byte("[1,2,3,4,5,6,7,8]") + _, err := rw.Write(data) + assert.Nil(t, err) + } else if req.URL.String() == "/invalid_body_api" { + data := []byte("Invalid") + _, err := rw.Write(data) + assert.Nil(t, err) + } else { + rw.WriteHeader(http.StatusInternalServerError) + data := []byte("") + _, err := rw.Write(data) + assert.Nil(t, err) + } + })) + defer server.Close() + + testCases := []struct { + name string + endpoint string + expected bool + }{ + { + name: "valid API", + endpoint: "/good_api", + expected: true, + }, + { + name: "invalid response status code", + endpoint: "/bad_api", + expected: false, + }, + { + name: "invalid response body", + endpoint: "/invalid_body_api", + expected: false, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + result := pingNginxPlusApiEndpoint(fmt.Sprintf("%s%s", server.URL, testCase.endpoint)) + assert.Equal(t, testCase.expected, result) + }) + } +} + +func TestPingStubStatusApiEndpoint(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { + if req.URL.String() == "/good_api" { + data := []byte(` +Active connections: 2 +server accepts handled requests + 18 18 3266 +Reading: 0 Writing: 1 Waiting: 1 + `) + _, err := rw.Write(data) + assert.Nil(t, err) + } else if req.URL.String() == "/invalid_body_api" { + data := []byte("Invalid") + _, err := rw.Write(data) + assert.Nil(t, err) + } else { + rw.WriteHeader(http.StatusInternalServerError) + data := []byte("") + _, err := rw.Write(data) + assert.Nil(t, err) + } + })) + defer server.Close() + + testCases := []struct { + name string + endpoint string + expected bool + }{ + { + name: "valid API", + endpoint: "/good_api", + expected: true, + }, + { + name: "invalid response status code", + endpoint: "/bad_api", + expected: false, + }, + { + name: "invalid response body", + endpoint: "/invalid_body_api", + expected: false, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + result := pingStubStatusApiEndpoint(fmt.Sprintf("%s%s", server.URL, testCase.endpoint)) + assert.Equal(t, testCase.expected, result) + }) + } +} diff --git a/src/core/environment.go b/src/core/environment.go index a25538148..67d8defab 100644 --- a/src/core/environment.go +++ b/src/core/environment.go @@ -509,8 +509,9 @@ func (env *EnvironmentType) Processes() (result []*Process) { p, _ := process.NewProcessWithContext(ctx, pid) name, _ := p.NameWithContext(ctx) + cmd, _ := p.CmdlineWithContext(ctx) - if name == "nginx" { + if name == "nginx" && !strings.Contains(cmd, "upgrade") { nginxProcesses[pid] = p } } diff --git a/test/integration/vendor/github.com/nginx/agent/sdk/v2/config_helpers.go b/test/integration/vendor/github.com/nginx/agent/sdk/v2/config_helpers.go index eccc5b749..8ad40b98c 100644 --- a/test/integration/vendor/github.com/nginx/agent/sdk/v2/config_helpers.go +++ b/test/integration/vendor/github.com/nginx/agent/sdk/v2/config_helpers.go @@ -10,8 +10,10 @@ package sdk import ( "crypto/sha256" "encoding/hex" + "encoding/json" "errors" "fmt" + "io" "io/fs" "net" "net/http" @@ -669,41 +671,46 @@ func AddAuxfileToNginxConfig( func parseAddressesFromServerDirective(parent *crossplane.Directive) []string { addresses := []string{} + hosts := []string{} port := "80" for _, dir := range parent.Block { - address := "127.0.0.1" + hostname := "127.0.0.1" switch dir.Directive { case "listen": host, listenPort, err := net.SplitHostPort(dir.Args[0]) if err == nil { if host == "*" || host == "" { - address = "127.0.0.1" + hostname = "127.0.0.1" } else if host == "::" || host == "::1" { - address = "[::1]" + hostname = "[::1]" } else { - address = host + hostname = host } port = listenPort } else { if isPort(dir.Args[0]) { port = dir.Args[0] } else { - address = dir.Args[0] + hostname = dir.Args[0] } } - addresses = append(addresses, fmt.Sprintf("%s:%s", address, port)) + hosts = append(hosts, hostname) case "server_name": if dir.Args[0] == "_" { // default server continue } - address = dir.Args[0] - addresses = append(addresses, fmt.Sprintf("%s:%s", address, port)) + hostname = dir.Args[0] + hosts = append(hosts, hostname) } } + for _, host := range hosts { + addresses = append(addresses, fmt.Sprintf("%s:%s", host, port)) + } + return addresses } @@ -729,7 +736,7 @@ func statusAPICallback(parent *crossplane.Directive, current *crossplane.Directi plusUrls := getUrlsForLocationDirective(parent, current, plusAPIDirective) for _, url := range plusUrls { - if pingStatusAPIEndpoint(url) { + if pingNginxPlusApiEndpoint(url) { log.Debugf("api at %q found", url) return url } @@ -737,7 +744,7 @@ func statusAPICallback(parent *crossplane.Directive, current *crossplane.Directi } for _, url := range ossUrls { - if pingStatusAPIEndpoint(url) { + if pingStubStatusApiEndpoint(url) { log.Debugf("stub_status at %q found", url) return url } @@ -747,16 +754,6 @@ func statusAPICallback(parent *crossplane.Directive, current *crossplane.Directi return "" } -// pingStatusAPIEndpoint ensures the statusAPI is reachable from the agent -func pingStatusAPIEndpoint(statusAPI string) bool { - client := http.Client{Timeout: 50 * time.Millisecond} - - if _, err := client.Head(statusAPI); err != nil { - return false - } - return true -} - // Deprecated: use either GetStubStatusApiUrl or GetNginxPlusApiUrl func GetStatusApiInfoWithIgnoreDirectives(confFile string, ignoreDirectives []string) (statusApi string, err error) { payload, err := crossplane.Parse(confFile, @@ -834,7 +831,7 @@ func stubStatusApiCallback(parent *crossplane.Directive, current *crossplane.Dir urls := getUrlsForLocationDirective(parent, current, stubStatusAPIDirective) for _, url := range urls { - if pingStatusAPIEndpoint(url) { + if pingStubStatusApiEndpoint(url) { log.Debugf("stub_status at %q found", url) return url } @@ -848,7 +845,7 @@ func nginxPlusApiCallback(parent *crossplane.Directive, current *crossplane.Dire urls := getUrlsForLocationDirective(parent, current, plusAPIDirective) for _, url := range urls { - if pingStatusAPIEndpoint(url) { + if pingNginxPlusApiEndpoint(url) { log.Debugf("plus API at %q found", url) return url } @@ -858,6 +855,56 @@ func nginxPlusApiCallback(parent *crossplane.Directive, current *crossplane.Dire return "" } +func pingStubStatusApiEndpoint(statusAPI string) bool { + client := http.Client{Timeout: 50 * time.Millisecond} + resp, err := client.Get(statusAPI) + if err != nil { + return false + } + + if resp.StatusCode != 200 { + return false + } + + bodyBytes, err := io.ReadAll(resp.Body) + if err != nil { + return false + } + + // Expecting API to return data like this: + // + // Active connections: 2 + // server accepts handled requests + // 18 18 3266 + // Reading: 0 Writing: 1 Waiting: 1 + body := string(bodyBytes) + return strings.Contains(body, "Active connections") && strings.Contains(body, "server accepts handled requests") +} + +func pingNginxPlusApiEndpoint(statusAPI string) bool { + client := http.Client{Timeout: 50 * time.Millisecond} + resp, err := client.Get(statusAPI) + if err != nil { + return false + } + + if resp.StatusCode != 200 { + return false + } + + bodyBytes, err := io.ReadAll(resp.Body) + if err != nil { + return false + } + + // Expecting API to return the api versions in an array of positive integers + // subset example: [ ... 6,7,8,9 ...] + var responseBody []int + err = json.Unmarshal(bodyBytes, &responseBody) + + return err == nil +} + func getUrlsForLocationDirective(parent *crossplane.Directive, current *crossplane.Directive, locationDirectiveName string) []string { var urls []string // process from the location block diff --git a/test/integration/vendor/github.com/nginx/agent/v2/src/core/environment.go b/test/integration/vendor/github.com/nginx/agent/v2/src/core/environment.go index a25538148..67d8defab 100644 --- a/test/integration/vendor/github.com/nginx/agent/v2/src/core/environment.go +++ b/test/integration/vendor/github.com/nginx/agent/v2/src/core/environment.go @@ -509,8 +509,9 @@ func (env *EnvironmentType) Processes() (result []*Process) { p, _ := process.NewProcessWithContext(ctx, pid) name, _ := p.NameWithContext(ctx) + cmd, _ := p.CmdlineWithContext(ctx) - if name == "nginx" { + if name == "nginx" && !strings.Contains(cmd, "upgrade") { nginxProcesses[pid] = p } } diff --git a/test/performance/vendor/github.com/nginx/agent/sdk/v2/config_helpers.go b/test/performance/vendor/github.com/nginx/agent/sdk/v2/config_helpers.go index eccc5b749..8ad40b98c 100644 --- a/test/performance/vendor/github.com/nginx/agent/sdk/v2/config_helpers.go +++ b/test/performance/vendor/github.com/nginx/agent/sdk/v2/config_helpers.go @@ -10,8 +10,10 @@ package sdk import ( "crypto/sha256" "encoding/hex" + "encoding/json" "errors" "fmt" + "io" "io/fs" "net" "net/http" @@ -669,41 +671,46 @@ func AddAuxfileToNginxConfig( func parseAddressesFromServerDirective(parent *crossplane.Directive) []string { addresses := []string{} + hosts := []string{} port := "80" for _, dir := range parent.Block { - address := "127.0.0.1" + hostname := "127.0.0.1" switch dir.Directive { case "listen": host, listenPort, err := net.SplitHostPort(dir.Args[0]) if err == nil { if host == "*" || host == "" { - address = "127.0.0.1" + hostname = "127.0.0.1" } else if host == "::" || host == "::1" { - address = "[::1]" + hostname = "[::1]" } else { - address = host + hostname = host } port = listenPort } else { if isPort(dir.Args[0]) { port = dir.Args[0] } else { - address = dir.Args[0] + hostname = dir.Args[0] } } - addresses = append(addresses, fmt.Sprintf("%s:%s", address, port)) + hosts = append(hosts, hostname) case "server_name": if dir.Args[0] == "_" { // default server continue } - address = dir.Args[0] - addresses = append(addresses, fmt.Sprintf("%s:%s", address, port)) + hostname = dir.Args[0] + hosts = append(hosts, hostname) } } + for _, host := range hosts { + addresses = append(addresses, fmt.Sprintf("%s:%s", host, port)) + } + return addresses } @@ -729,7 +736,7 @@ func statusAPICallback(parent *crossplane.Directive, current *crossplane.Directi plusUrls := getUrlsForLocationDirective(parent, current, plusAPIDirective) for _, url := range plusUrls { - if pingStatusAPIEndpoint(url) { + if pingNginxPlusApiEndpoint(url) { log.Debugf("api at %q found", url) return url } @@ -737,7 +744,7 @@ func statusAPICallback(parent *crossplane.Directive, current *crossplane.Directi } for _, url := range ossUrls { - if pingStatusAPIEndpoint(url) { + if pingStubStatusApiEndpoint(url) { log.Debugf("stub_status at %q found", url) return url } @@ -747,16 +754,6 @@ func statusAPICallback(parent *crossplane.Directive, current *crossplane.Directi return "" } -// pingStatusAPIEndpoint ensures the statusAPI is reachable from the agent -func pingStatusAPIEndpoint(statusAPI string) bool { - client := http.Client{Timeout: 50 * time.Millisecond} - - if _, err := client.Head(statusAPI); err != nil { - return false - } - return true -} - // Deprecated: use either GetStubStatusApiUrl or GetNginxPlusApiUrl func GetStatusApiInfoWithIgnoreDirectives(confFile string, ignoreDirectives []string) (statusApi string, err error) { payload, err := crossplane.Parse(confFile, @@ -834,7 +831,7 @@ func stubStatusApiCallback(parent *crossplane.Directive, current *crossplane.Dir urls := getUrlsForLocationDirective(parent, current, stubStatusAPIDirective) for _, url := range urls { - if pingStatusAPIEndpoint(url) { + if pingStubStatusApiEndpoint(url) { log.Debugf("stub_status at %q found", url) return url } @@ -848,7 +845,7 @@ func nginxPlusApiCallback(parent *crossplane.Directive, current *crossplane.Dire urls := getUrlsForLocationDirective(parent, current, plusAPIDirective) for _, url := range urls { - if pingStatusAPIEndpoint(url) { + if pingNginxPlusApiEndpoint(url) { log.Debugf("plus API at %q found", url) return url } @@ -858,6 +855,56 @@ func nginxPlusApiCallback(parent *crossplane.Directive, current *crossplane.Dire return "" } +func pingStubStatusApiEndpoint(statusAPI string) bool { + client := http.Client{Timeout: 50 * time.Millisecond} + resp, err := client.Get(statusAPI) + if err != nil { + return false + } + + if resp.StatusCode != 200 { + return false + } + + bodyBytes, err := io.ReadAll(resp.Body) + if err != nil { + return false + } + + // Expecting API to return data like this: + // + // Active connections: 2 + // server accepts handled requests + // 18 18 3266 + // Reading: 0 Writing: 1 Waiting: 1 + body := string(bodyBytes) + return strings.Contains(body, "Active connections") && strings.Contains(body, "server accepts handled requests") +} + +func pingNginxPlusApiEndpoint(statusAPI string) bool { + client := http.Client{Timeout: 50 * time.Millisecond} + resp, err := client.Get(statusAPI) + if err != nil { + return false + } + + if resp.StatusCode != 200 { + return false + } + + bodyBytes, err := io.ReadAll(resp.Body) + if err != nil { + return false + } + + // Expecting API to return the api versions in an array of positive integers + // subset example: [ ... 6,7,8,9 ...] + var responseBody []int + err = json.Unmarshal(bodyBytes, &responseBody) + + return err == nil +} + func getUrlsForLocationDirective(parent *crossplane.Directive, current *crossplane.Directive, locationDirectiveName string) []string { var urls []string // process from the location block diff --git a/test/performance/vendor/github.com/nginx/agent/v2/src/core/environment.go b/test/performance/vendor/github.com/nginx/agent/v2/src/core/environment.go index a25538148..67d8defab 100644 --- a/test/performance/vendor/github.com/nginx/agent/v2/src/core/environment.go +++ b/test/performance/vendor/github.com/nginx/agent/v2/src/core/environment.go @@ -509,8 +509,9 @@ func (env *EnvironmentType) Processes() (result []*Process) { p, _ := process.NewProcessWithContext(ctx, pid) name, _ := p.NameWithContext(ctx) + cmd, _ := p.CmdlineWithContext(ctx) - if name == "nginx" { + if name == "nginx" && !strings.Contains(cmd, "upgrade") { nginxProcesses[pid] = p } } diff --git a/vendor/github.com/nginx/agent/sdk/v2/config_helpers.go b/vendor/github.com/nginx/agent/sdk/v2/config_helpers.go index eccc5b749..8ad40b98c 100644 --- a/vendor/github.com/nginx/agent/sdk/v2/config_helpers.go +++ b/vendor/github.com/nginx/agent/sdk/v2/config_helpers.go @@ -10,8 +10,10 @@ package sdk import ( "crypto/sha256" "encoding/hex" + "encoding/json" "errors" "fmt" + "io" "io/fs" "net" "net/http" @@ -669,41 +671,46 @@ func AddAuxfileToNginxConfig( func parseAddressesFromServerDirective(parent *crossplane.Directive) []string { addresses := []string{} + hosts := []string{} port := "80" for _, dir := range parent.Block { - address := "127.0.0.1" + hostname := "127.0.0.1" switch dir.Directive { case "listen": host, listenPort, err := net.SplitHostPort(dir.Args[0]) if err == nil { if host == "*" || host == "" { - address = "127.0.0.1" + hostname = "127.0.0.1" } else if host == "::" || host == "::1" { - address = "[::1]" + hostname = "[::1]" } else { - address = host + hostname = host } port = listenPort } else { if isPort(dir.Args[0]) { port = dir.Args[0] } else { - address = dir.Args[0] + hostname = dir.Args[0] } } - addresses = append(addresses, fmt.Sprintf("%s:%s", address, port)) + hosts = append(hosts, hostname) case "server_name": if dir.Args[0] == "_" { // default server continue } - address = dir.Args[0] - addresses = append(addresses, fmt.Sprintf("%s:%s", address, port)) + hostname = dir.Args[0] + hosts = append(hosts, hostname) } } + for _, host := range hosts { + addresses = append(addresses, fmt.Sprintf("%s:%s", host, port)) + } + return addresses } @@ -729,7 +736,7 @@ func statusAPICallback(parent *crossplane.Directive, current *crossplane.Directi plusUrls := getUrlsForLocationDirective(parent, current, plusAPIDirective) for _, url := range plusUrls { - if pingStatusAPIEndpoint(url) { + if pingNginxPlusApiEndpoint(url) { log.Debugf("api at %q found", url) return url } @@ -737,7 +744,7 @@ func statusAPICallback(parent *crossplane.Directive, current *crossplane.Directi } for _, url := range ossUrls { - if pingStatusAPIEndpoint(url) { + if pingStubStatusApiEndpoint(url) { log.Debugf("stub_status at %q found", url) return url } @@ -747,16 +754,6 @@ func statusAPICallback(parent *crossplane.Directive, current *crossplane.Directi return "" } -// pingStatusAPIEndpoint ensures the statusAPI is reachable from the agent -func pingStatusAPIEndpoint(statusAPI string) bool { - client := http.Client{Timeout: 50 * time.Millisecond} - - if _, err := client.Head(statusAPI); err != nil { - return false - } - return true -} - // Deprecated: use either GetStubStatusApiUrl or GetNginxPlusApiUrl func GetStatusApiInfoWithIgnoreDirectives(confFile string, ignoreDirectives []string) (statusApi string, err error) { payload, err := crossplane.Parse(confFile, @@ -834,7 +831,7 @@ func stubStatusApiCallback(parent *crossplane.Directive, current *crossplane.Dir urls := getUrlsForLocationDirective(parent, current, stubStatusAPIDirective) for _, url := range urls { - if pingStatusAPIEndpoint(url) { + if pingStubStatusApiEndpoint(url) { log.Debugf("stub_status at %q found", url) return url } @@ -848,7 +845,7 @@ func nginxPlusApiCallback(parent *crossplane.Directive, current *crossplane.Dire urls := getUrlsForLocationDirective(parent, current, plusAPIDirective) for _, url := range urls { - if pingStatusAPIEndpoint(url) { + if pingNginxPlusApiEndpoint(url) { log.Debugf("plus API at %q found", url) return url } @@ -858,6 +855,56 @@ func nginxPlusApiCallback(parent *crossplane.Directive, current *crossplane.Dire return "" } +func pingStubStatusApiEndpoint(statusAPI string) bool { + client := http.Client{Timeout: 50 * time.Millisecond} + resp, err := client.Get(statusAPI) + if err != nil { + return false + } + + if resp.StatusCode != 200 { + return false + } + + bodyBytes, err := io.ReadAll(resp.Body) + if err != nil { + return false + } + + // Expecting API to return data like this: + // + // Active connections: 2 + // server accepts handled requests + // 18 18 3266 + // Reading: 0 Writing: 1 Waiting: 1 + body := string(bodyBytes) + return strings.Contains(body, "Active connections") && strings.Contains(body, "server accepts handled requests") +} + +func pingNginxPlusApiEndpoint(statusAPI string) bool { + client := http.Client{Timeout: 50 * time.Millisecond} + resp, err := client.Get(statusAPI) + if err != nil { + return false + } + + if resp.StatusCode != 200 { + return false + } + + bodyBytes, err := io.ReadAll(resp.Body) + if err != nil { + return false + } + + // Expecting API to return the api versions in an array of positive integers + // subset example: [ ... 6,7,8,9 ...] + var responseBody []int + err = json.Unmarshal(bodyBytes, &responseBody) + + return err == nil +} + func getUrlsForLocationDirective(parent *crossplane.Directive, current *crossplane.Directive, locationDirectiveName string) []string { var urls []string // process from the location block